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.


POST/promotion/generate-payment-code

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

  • 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
    email
    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_discount for this transaction. Hard-capped by the device's channel_kickback margin — requests where discount > channel_kickback are rejected with 422.

Behavior

  • Validates the device, organization, and promotion
  • Resolves the effective discount: if discount is supplied it replaces the device's channel_discount for this transaction; otherwise the device default is used
  • Rejects with 422 when the supplied discount exceeds the device's channel_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

POST
/promotion/generate-payment-code
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"
    },
    "expiration_date": "2025-04-15 14:30:00"
  }
}

Error - Discount Exceeds Cap

{
  "status": false,
  "message": "Discount exceeds channel kickback (max 10%)"
}

POST/promotion/check-code-status

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 = true OR 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:

  1. First device on code.location_id
  2. code.device_id (fallback when location has no device)
  3. 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=svg where {value} is:
    • Product's cash_register_column when code.product_id is set
    • Location device's device_promotion.reference if no product reference exists
    • Falls back to the WLNT code if neither is set

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=pngimage/png | | /barcode/{value} | image/png | ?format=svgimage/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

  • 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 creation, activation, redemption, and expiration
  • 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=svg is appended by the server; clients can swap to ?format=png for iOS rendering.

Request

POST
/promotion/check-code-status
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",
      "activation_date": "2025-01-15 11:00:00",
      "redeemed_at": null,
      "expiration_date": "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",
      "activation_date": "2025-01-15 11:00:00",
      "redeemed_at": null,
      "expiration_date": "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",
      "activation_date": "2025-01-15 11:00:00",
      "redeemed_at": null,
      "expiration_date": "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",
      "activation_date": "2025-01-15 11:00:00",
      "redeemed_at": null,
      "expiration_date": "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",
      "activation_date": "2025-01-10 09:30:00",
      "redeemed_at": "2025-01-12 14:20:00",
      "expiration_date": "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"
    }
  }
}

POST/promotion/activate-paid-code

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 409 if the code still requires payment (bijbetaling_required is true and bijbetaling_paid is false).
  • Refuses with 409 if the code is already active (activation_date is set).
  • Stamps activation_date = now().
  • Sets expiration_date to now() + N days, where N is the redemption location device's staffel_redemption_days (defaults to 60 when not configured).
  • Once activated, /promotion/check-code-status returns the barcode/QR image URL for the code.

Response fields

  • Name
    success
    Type
    boolean
    Description

    true when 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.activation_date
    Type
    string
    Description

    Timestamp the activation was stamped (Y-m-d H:i:s).

  • Name
    data.expiration_date
    Type
    string
    Description

    New expiration timestamp (Y-m-d H:i:s).

Request

POST
/promotion/activate-paid-code
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"
  }'

POST/promotion/codes-by-email

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

  • 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
    email
    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

POST
/promotion/codes-by-email
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",
          "activation_date": "2025-01-15 11:00:00",
          "redeemed_at": "2025-01-16 14:20:00",
          "expiration_date": "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",
          "activation_date": null,
          "redeemed_at": null,
          "expiration_date": "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
        }
      }
    ]
  }
}

POST/promotion/codes-by-customer-identifier

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

  • 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

POST
/promotion/codes-by-customer-identifier
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",
          "activation_date": "2025-01-15 11:00:00",
          "redeemed_at": "2025-01-16 14:20:00",
          "expiration_date": "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",
          "activation_date": null,
          "redeemed_at": null,
          "expiration_date": "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": []
  }
}