Reseller Orders
These endpoints allow resellers to generate promotion codes that require payment (bijbetaling), check code status, and retrieve all codes associated with a customer email address or customer identifier.
Generate payment code
Creates a promotion code that requires payment before activation. The payment amount is calculated based on the product price minus any scanner discount configured on the device.
Required headers
This API requires a Device Token. These tokens are generated in the dashboard by navigating to "Scanners" and clicking the key icon.
- Name
Authorization- Type
- string
- Description
Bearer token of the authenticated device.
Request body
- Name
organization_identifier- Type
- string
- Description
Identifier of the organization.
- Name
promotion_identifier- Type
- string
- Description
UUID of the promotion.
- Name
product_id- Type
- integer
- Description
ID of the product to be purchased.
- Name
location_id- Type
- integer
- Description
ID of the location where the code will be activated.
- Name
email- Type
- Description
Customer email address. If provided, a user account will be created or linked. Either email or customer_identifier must be provided.
- Name
customer_identifier- Type
- string
- Description
Unique external identifier for the customer (e.g., loyalty ID, customer number). Used to track customers across channels without requiring an email address. Either email or customer_identifier must be provided.
- Name
discount- Type
- number
- Description
Per-request discount percentage applied to the product price (0-100). When supplied, this value is used in place of the device's default
channel_discountfor this transaction. Hard-capped by the device'schannel_kickbackmargin — requests wherediscount > channel_kickbackare rejected with422.
Behavior
- Validates the device, organization, and promotion
- Resolves the effective discount: if
discountis supplied it replaces the device'schannel_discountfor this transaction; otherwise the device default is used - Rejects with
422when the supplieddiscountexceeds the device'schannel_kickback - Calculates payment amount:
price - (price * effective_discount / 100) - Creates or links user account if email is provided
- If customer_identifier is provided, creates or links external_user record for cross-channel tracking
- Generates a unique promotion code with payment requirement
- Creates Mollie payment directly and returns checkout URL for immediate payment
- Stores external_user_id in promotion_codes table for customer_identifier lookups
- Code expires in 91 days from creation
Request
curl -X POST "https://api.walletapp.co/promotion/generate-payment-code" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"organization_identifier": "9jYwYpYhu1vWrWsSRlshURzf0a",
"promotion_identifier": "1cfd74ec-d085-4d05-9b8f-e436c68132ef",
"product_id": 5377,
"location_id": 1,
"email": "customer@example.com",
"customer_identifier": "1444"
}'
Response
{
"success": true,
"message": "Bijbetaling payment created successfully",
"data": {
"code": "WLNT-ABC-DEF-GHI2",
"checkout_url": "https://www.mollie.com/payscreen/select-method/7UhSN1zuXS",
"order_id": "BIJ-XKPNQW9T7L",
"email": "customer@example.com",
"customer_identifier": "1444",
"user_id": 12345,
"external_user_id": 789,
"product": {
"id": 5377,
"title": "Premium Car Wash",
"original_price": "25.00"
},
"location": {
"id": 1,
"title": "Main Street Location"
},
"bijbetaling": {
"amount": "20.00",
"discount_percentage": 20,
"currency": "EUR"
},
"expires_at": "2025-04-15 14:30:00"
}
}
Error - Discount Exceeds Cap
{
"status": false,
"message": "Discount exceeds channel kickback (max 10%)"
}
Check code status
Retrieves the current status of a promotion code, including activation status, redemption status, payment status, and location information.
QR Code / Barcode Availability
The qr_image_url field is only included in the response when all of the following conditions are met:
- Code is activated (
status.activated = true) - Code is paid (
status.paid = trueOR no payment required) - Code is not redeemed (
status.redeemed = false)
This ensures the code image is only shown when the code is ready to be scanned at a location.
QR vs Barcode
The format follows the device configured at the location the customer activated against — not the requesting device. Resolution order:
- First device on
code.location_id code.device_id(fallback when location has no device)- Querying device (final fallback for legacy codes with no location bound)
Using the customer-bound device guarantees the format matches what the redemption location's scanner expects, regardless of which integration partner makes the check-code-status call.
- QR Code: For standard scanning devices, returns
/qrcode/{code}with the WLNT code. - Barcode: For manual entry devices (
response_type = 'manual'), returns/barcode/{value}?format=svgwhere{value}is:- Product's
cash_register_columnwhencode.product_idis set - Location device's
device_promotion.referenceif no product reference exists - Falls back to the WLNT code if neither is set
- Product's
Image format (/qrcode/... and /barcode/...)
Both endpoints accept an optional ?format= query parameter so consumers can pick the format that renders best in their environment.
| Endpoint | Default response | Opt-in via query param |
| --- | --- | --- |
| /qrcode/{code} | image/svg+xml | ?format=png → image/png |
| /barcode/{value} | image/png | ?format=svg → image/svg+xml |
The barcode URL returned by qr_image_url already includes ?format=svg so most consumers don't need to think about this. iOS clients (PassKit, certain in-app webviews) render PNG more reliably than SVG — append ?format=png to the returned qr_image_url (or replace the existing ?format=svg) when rendering on iOS:
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent);
let url = data.qr_image_url;
if (isIos) {
url = url.replace(/([?&])format=svg/, '$1format=png');
if (!url.includes('format=')) {
url += (url.includes('?') ? '&' : '?') + 'format=png';
}
}
Cache keys are per-variant so PNG and SVG responses don't poison each other.
Required headers
This API requires a Device Token. These tokens are generated in the dashboard by navigating to "Scanners" and clicking the key icon.
- Name
Authorization- Type
- string
- Description
Bearer token of the authenticated device.
Request body
- Name
organization_identifier- Type
- string
- Description
Identifier of the organization.
- Name
promotion_identifier- Type
- string
- Description
UUID of the promotion.
- Name
code- Type
- string
- Description
The promotion code to check (e.g., "WLNT-ABC-DEF-GHI2").
Response fields
- status: Boolean flags for activated, redeemed, and paid
- dates: Timestamps for
created_at,activated_at,redeemed_at, andexpires_at— allY-m-d H:i:s.expires_atis the authoritative expiry instant, driven off the timestamp column; for barcode codes that's the precise 1-hour-after-activation moment. (The earlieractivation_date/expiration_date/expiration_timestampnames were replaced by this standardized*_atset.) - user: Email (if provided when creating code) and external_identifier (customer_identifier if provided when creating code)
- redemption_location: Where the code was redeemed (if redeemed)
- bijbetaling: Payment requirement details including amount and payment status
- qr_image_url: QR code or barcode image URL (only included when code is activated, paid, and not redeemed). The endpoint and default format depend on the customer's location device (see QR vs Barcode above). For barcodes,
?format=svgis appended by the server; clients can swap to?format=pngfor iOS rendering. - barcode_fetch_count / barcode_fetch_limit / barcode_fetch_exhausted: Present only for manual/barcode codes (
requires_manual_activation = true). The count increments on every call that returnsqr_image_url; oncefetch_count == fetch_limitthe URL is withheld andfetch_exhaustedflips totrue. See Activate a paid bijbetaling code for the full rate-limit semantics.
Request
curl -X POST "https://api.walletapp.co/promotion/check-code-status" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"organization_identifier": "9jYwYpYhu1vWrWsSRlshURzf0a",
"promotion_identifier": "1cfd74ec-d085-4d05-9b8f-e436c68132ef",
"code": "WLNT-ABC-DEF-GHI2"
}'
Response - Code Ready for Redemption
{
"success": true,
"data": {
"code": "WLNT-ABC-DEF-GHI2",
"status": {
"activated": true,
"redeemed": false,
"paid": true
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": null,
"expires_at": "2025-04-15 10:30:00"
},
"user": {
"email": "customer@example.com",
"external_identifier": null
},
"redemption_location": null,
"qr_image_url": "https://api.walletapp.co/qrcode/WLNT-ABC-DEF-GHI2",
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-15 10:45:00"
}
}
}
Response - Code with Customer Identifier
{
"success": true,
"data": {
"code": "WLNT-ABC-DEF-GHI2",
"status": {
"activated": true,
"redeemed": false,
"paid": true
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": null,
"expires_at": "2025-04-15 10:30:00"
},
"user": {
"email": null,
"external_identifier": "1444"
},
"redemption_location": null,
"qr_image_url": "https://api.walletapp.co/qrcode/WLNT-ABC-DEF-GHI2",
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-15 10:45:00"
}
}
}
Response - Code Not Ready (Not Paid)
{
"success": true,
"data": {
"code": "WLNT-XYZ-789-DEF3",
"status": {
"activated": true,
"redeemed": false,
"paid": false
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": null,
"expires_at": "2025-04-15 10:30:00"
},
"user": {
"email": "customer@example.com",
"external_identifier": null
},
"redemption_location": null,
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": false,
"paid_at": null
}
}
}
Response - Barcode for Manual Device
{
"success": true,
"data": {
"code": "WLNT-ABC-DEF-GHI2",
"status": {
"activated": true,
"redeemed": false,
"paid": true
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": null,
"expires_at": "2025-04-15 10:30:00"
},
"user": {
"email": "customer@example.com",
"external_identifier": null
},
"redemption_location": null,
"qr_image_url": "https://api.walletapp.co/barcode/12345?format=svg",
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-15 10:45:00"
}
}
}
Response - Code Already Redeemed
{
"success": true,
"data": {
"code": "WLNT-ABC-123-XYZ9",
"status": {
"activated": true,
"redeemed": true,
"paid": true
},
"dates": {
"created_at": "2025-01-10 09:00:00",
"activated_at": "2025-01-10 09:30:00",
"redeemed_at": "2025-01-12 14:20:00",
"expires_at": "2025-04-10 09:00:00"
},
"user": {
"email": "customer@example.com",
"external_identifier": null
},
"redemption_location": {
"id": 5,
"title": "Downtown Location",
"address": "456 Main St, City"
},
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-10 09:15:00"
}
}
}
Activate a paid bijbetaling code
Activates a scanner-issued bijbetaling code after the customer has paid through Mollie. This endpoint exists for codes that were created via /promotion/generate-payment-code against a redemption location whose device is a barcode/manual scanner (response_type = 'manual'). Those codes are intentionally held in an inactive state after payment so the scanner can decide when they become redeemable.
For QR-code redemption devices the Mollie webhook activates the code automatically — this endpoint is not required.
Required headers
- Name
Authorization- Type
- string
- Description
Bearer token of the authenticated scanner device. The device must belong to the supplied organization.
Request body
- Name
organization_identifier- Type
- string
- Description
Identifier of the organization the device belongs to.
- Name
promotion_identifier- Type
- string
- Description
UUID of the promotion the code belongs to.
- Name
code- Type
- string
- Description
The full
WLNT-…promotion code that was returned by/promotion/generate-payment-code.
Behavior
- Authenticates the device via bearer token and verifies it is bound to the supplied organization.
- Looks up the code under the supplied promotion.
- Refuses with
409if the code still requires payment (bijbetaling_requiredistrueandbijbetaling_paidisfalse). - Refuses with
409if the code is already active (activated_atis set). - Stamps
activated_at = now(). - Sets
expires_at: for barcode (manual) devices the code is valid 1 hour after activation (immediate use at the register); for QR / non-manual devices it isnow() + staffel_redemption_days(default60). - Marks the code redeemed (
redeemed_at) one hour after activation — these reseller codes are activate-and-use, so a separate redemption call is not required. Redemption attribution for the partner location's monthly invoice is handled by Walletapp once the activation has been recorded; no additional API call is needed from the integration side. - On success the response includes
data.qr_image_url— the barcode/QR image the scanner should display — resolved exactly as/promotion/check-code-statusresolves it, so you do not need a second call to fetch it. The same URL remains available fromcheck-code-statusafterwards, rate-limited to a small number of refetches (see thebarcode_fetch_count/barcode_fetch_limitfields).
Response fields
- Name
success- Type
- boolean
- Description
truewhen the code has been activated.
- Name
message- Type
- string
- Description
Human-readable status message.
- Name
data.code- Type
- string
- Description
The activated promotion code.
- Name
data.activated_at- Type
- string
- Description
Timestamp the activation was stamped (
Y-m-d H:i:s).
- Name
data.redeemed_at- Type
- string
- Description
Timestamp the code is recorded as redeemed (
Y-m-d H:i:s) — one hour after activation (these reseller codes are activate-and-use).
- Name
data.expires_at- Type
- string
- Description
Single authoritative expiry instant (
Y-m-d H:i:s). For barcode codes activated through this endpoint that'sactivated_at + 1 hour— after which the barcode is no longer valid for redemption. Returned in the same shape by/promotion/check-code-status.
- Name
data.barcode_fetch_count- Type
- integer
- Description
Number of times the barcode image URL has been issued for this code, starting at
1immediately after activation. Increments on every/promotion/check-code-statuscall that returnsqr_image_url. Oncebarcode_fetch_count == barcode_fetch_limitthe URL is withheld.
- Name
data.barcode_fetch_limit- Type
- integer
- Description
Hard cap on barcode image refetches per code (currently
10). Together withbarcode_fetch_countlets the scanner show the cashier how many displays remain.
- Name
data.barcode_fetch_exhausted- Type
- boolean
- Description
truewhenbarcode_fetch_counthas reachedbarcode_fetch_limit. The response will no longer includeqr_image_url.
- Name
data.qr_image_url- Type
- string
- Description
Barcode/QR image URL for the activated code. Only included when the code is activated, paid (or no payment required), and not redeemed — i.e. the normal state immediately after a successful activation. The endpoint and default format depend on the customer's location device (see QR vs Barcode): manual/barcode devices return a barcode URL with
?format=svgappended, which clients can swap to?format=pngfor iOS rendering.
Request
curl -X POST "https://api.walletapp.co/promotion/activate-paid-code" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"organization_identifier": "org-123",
"promotion_identifier": "promo-uuid",
"code": "WLNT-ABC123XYZ9Z9"
}'
Get user codes by email
Retrieves all promotion codes associated with an email address for a specific promotion, including their status, dates, locations, and payment information.
Required headers
This API requires a Device Token. These tokens are generated in the dashboard by navigating to "Scanners" and clicking the key icon.
- Name
Authorization- Type
- string
- Description
Bearer token of the authenticated device.
Request body
- Name
organization_identifier- Type
- string
- Description
Identifier of the organization.
- Name
promotion_identifier- Type
- string
- Description
UUID of the promotion.
- Name
email- Type
- Description
Customer email address to search for.
Response fields
For each code found:
- code: The promotion code string
- status: Activation, redemption, and payment status
- dates: All relevant timestamps
- locations: Both activation and redemption locations (with address)
- product: Product details if linked
- bijbetaling: Payment requirement and status
Request
curl -X POST "https://api.walletapp.co/promotion/codes-by-email" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"organization_identifier": "9jYwYpYhu1vWrWsSRlshURzf0a",
"promotion_identifier": "1cfd74ec-d085-4d05-9b8f-e436c68132ef",
"email": "customer@example.com"
}'
Response
{
"success": true,
"message": "Codes retrieved successfully",
"data": {
"email": "customer@example.com",
"total_codes": 3,
"codes": [
{
"code": "WLNT-ABC-DEF-GHI2",
"status": {
"activated": true,
"redeemed": true,
"paid": true
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": "2025-01-16 14:20:00",
"expires_at": "2025-04-15 10:30:00"
},
"locations": {
"activation_location": {
"id": 1,
"title": "Main Street Location",
"address": "123 Main St, City"
},
"redemption_location": {
"id": 2,
"title": "Downtown Location",
"address": "456 Downtown Ave, City"
}
},
"product": {
"id": 5377,
"title": "Premium Car Wash",
"price": "25.00"
},
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-15 10:45:00"
}
},
{
"code": "WLNT-XYZ-123-ABC7",
"status": {
"activated": false,
"redeemed": false,
"paid": false
},
"dates": {
"created_at": "2025-01-20 09:15:00",
"activated_at": null,
"redeemed_at": null,
"expires_at": "2025-04-20 09:15:00"
},
"locations": {
"activation_location": null,
"redemption_location": null
},
"product": {
"id": 5378,
"title": "Basic Wash",
"price": "15.00"
},
"bijbetaling": {
"required": true,
"amount": "12.00",
"paid": false,
"paid_at": null
}
}
]
}
}
Get user codes by customer identifier
Retrieves all promotion codes associated with a customer identifier for a specific promotion. This endpoint is useful for looking up codes for customers who don't have email addresses but are tracked via external identifiers (e.g., loyalty IDs, customer numbers).
Required headers
This API requires a Device Token. These tokens are generated in the dashboard by navigating to "Scanners" and clicking the key icon.
- Name
Authorization- Type
- string
- Description
Bearer token of the authenticated device.
Request body
- Name
organization_identifier- Type
- string
- Description
Identifier of the organization.
- Name
promotion_identifier- Type
- string
- Description
UUID of the promotion.
- Name
customer_identifier- Type
- string
- Description
Customer identifier to search for (e.g., loyalty ID, customer number).
Response fields
For each code found:
- code: The promotion code string
- status: Activation, redemption, and payment status
- dates: All relevant timestamps
- locations: Both activation and redemption locations (with address)
- product: Product details if linked
- bijbetaling: Payment requirement and status
Behavior
- Searches for external_user by customer_identifier and device channel
- Returns all codes associated with that external user for the specified promotion
- Returns empty array if no external user or codes are found
Request
curl -X POST "https://api.walletapp.co/promotion/codes-by-customer-identifier" \
-H "Authorization: Bearer <your_token>" \
-H "Content-Type: application/json" \
-d '{
"organization_identifier": "9jYwYpYhu1vWrWsSRlshURzf0a",
"promotion_identifier": "1cfd74ec-d085-4d05-9b8f-e436c68132ef",
"customer_identifier": "1444"
}'
Response
{
"success": true,
"message": "Codes retrieved successfully",
"data": {
"customer_identifier": "1444",
"total_codes": 2,
"codes": [
{
"code": "WLNT-ABC-DEF-GHI2",
"status": {
"activated": true,
"redeemed": true,
"paid": true
},
"dates": {
"created_at": "2025-01-15 10:30:00",
"activated_at": "2025-01-15 11:00:00",
"redeemed_at": "2025-01-16 14:20:00",
"expires_at": "2025-04-15 10:30:00"
},
"locations": {
"activation_location": {
"id": 1,
"title": "Main Street Location",
"address": "123 Main St, City"
},
"redemption_location": {
"id": 2,
"title": "Downtown Location",
"address": "456 Downtown Ave, City"
}
},
"product": {
"id": 5377,
"title": "Premium Car Wash",
"price": "25.00"
},
"bijbetaling": {
"required": true,
"amount": "20.00",
"paid": true,
"paid_at": "2025-01-15 10:45:00"
}
},
{
"code": "WLNT-XYZ-123-ABC7",
"status": {
"activated": false,
"redeemed": false,
"paid": false
},
"dates": {
"created_at": "2025-01-20 09:15:00",
"activated_at": null,
"redeemed_at": null,
"expires_at": "2025-04-20 09:15:00"
},
"locations": {
"activation_location": null,
"redemption_location": null
},
"product": {
"id": 5378,
"title": "Basic Wash",
"price": "15.00"
},
"bijbetaling": {
"required": true,
"amount": "12.00",
"paid": false,
"paid_at": null
}
}
]
}
}
Response - No Codes Found
{
"success": true,
"message": "No codes found for this customer identifier",
"data": {
"customer_identifier": "1444",
"total_codes": 0,
"codes": []
}
}
