Checkout API
Checkout API
Checkout-Prozesse und Bestellabläufe in eigene Anwendungen integrieren.
https://checkout-clients-live-eu.qnips.com/Clients
Menus
Baskets & Orders
Profiles
/api/v1/profiles/{reference}POSTtop-ups/api/v1/profiles/{reference}/balance/top-upsPOSTcharges/api/v1/profiles/{reference}/balance/chargesPOSTrefunds/api/v1/profiles/{reference}/balance/refundsPOSTpayouts/api/v1/profiles/{reference}/balance/payoutsPOSTreservations/api/v1/profiles/{reference}/balance/reservationsCheck-ins
Grundlagen & vollständige Einführung
Welcome to the menio Checkout API. This API provides access to the checkout service.
ATTENTION
This documentation is still under development. Breaking changes and updates can be expected throughout the v1 version.
General information
From here on, we'll refer to the menio Checkout API simply as the "API".
Environments
The API is available in two separate environments:
Live environment: used for production traffic and real customer data.
Sandbox environment: used for development, testing and integration.
Each environment exposes the same API structure and functionality but differs in data persistence, rate limits, and operational guarantees.
Environment URLs
| Environment | Base URL |
|---|---|
| Live | https://checkout-clients-live-eu.qnips.com |
| Sandbox | https://checkout-clients-sandbox-eu.qnips.com |
Accessing a different environment only requires changing the base URL and using the appropriate authorization details.
No code changes should be required if your integration follows the API contract consistently.
Requests
All requests to the API must be performed over secure transport channels. All requests should use the HTTPS protocol and a minimum TLS version of 1.2.
Requests made over HTTP will be redirected to HTTPS.
Requests using deprecated TLS versions are rejected.
All requests to the API must follow the conventions below.
API versioning
The API is versioned to allow backward-incompatible changes without breaking existing clients. Upgrading to a new version can require updates to existing code.
Each API version is exposed through a dedicated URI path. When sending requests to the API, the client must specify the API version directly in the request URI:
GET {baseUrl}/api/v1/{resource}
Clients should:
Periodically review version deprecation notices.
Test integrations against newer versions.
Plan migrations early to avoid disruption.
Authorization Header
All requests to protected endpoints must provide one of the supported Authorization headers:
| Schema | Example |
|---|---|
| Basic | Authorization: Basic <base64(<clientId>:<clientSecret>)> |
| ApiKey | Authorization: ApiKey <key> |
| Token | Authorization: Token <token> |
Please check the API reference and examples, to pick the right schema for the right resource.
Idempotency
Idempotency ensures that performing the same API request multiple times results in the same outcome as performing it once.
This mechanism protects both clients and backend systems from unintended side effects caused by retries, network issues, or duplicate submissions.
By assigning a unique idempotency key to each logical operation, clients can safely resend requests for 24 hours without risking duplicated charges, repeated state changes, or inconsistent data.
For POST requests that create resources, the API supports idempotent requests via the Idempotency-Key header:
Idempotency-Key: <unique-key-per-logical-operation>
The key must be a
V4 UUID/GUIDand is generated by the client.The key must be unique per logical operation (e.g., per order attempt).
If the same API request is submitted multiple times, the API responds based on the state of the original request:
| Code | Description |
|---|---|
200 |
OK - A previous instance of this request has been successfully processed within the past 24 hours, and the API returns the original response. |
202 |
Accepted - A previous instance of this request is still being processed. If this occurs frequently, consider increasing your timeouts and retry using exponential backoff. |
422 |
Unprocessable Content - A request with the same Idempotency-Key was submitted, but the request body differs. The API rejects the request. |
Security token
Some security-critical endpoints require an additional Security-Token on top of API key or access token authentication.
This prevents attackers from using intercepted data to perform sensitive actions.
A valid Security-Token cannot be created without the clients securityKey, intercepted requests quickly become unusable, modified requests are rejected, and replayed requests are detected and handled safely.
Obtaining a Security-Token alone is not sufficient to create or submit new requests, as reused idempotency keys are detected and blocked.
Security-Token generation
The Security-Token is a HMACSHA256 hash of a number of request properties
that assures message integrity and prevents misuse by actors not in posession
of the securityKey obtained in client registration.
Requests with a Security-Token also require a Timestamp header, containing the
request UTC timestamp of the client in the format: yyyy-MM-ddTHH:mm:ssZ
Example: 2026-02-23T11:56:49Z
In order to generate the binary input data for the hash, build the following string with your request data and UTF8 encode it:
{requestMethod};{requestUrlIncludingQuery};{timestampHeader}
If the request has an Idempotency-Key header, append the binary representation of the UUID/GUID used as Idempotency-Key.
The UUID/GUID is encoded in normal reading order from left to right with regard to the common format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
i.e. removing the "-" segment delimiters will produce the hex representation of the data.
If the request has a body, further append the SHA256 hash of the request body.
Having generated the binary input data, use the securityKey the client received during registration to HMACSHA256 hash this data.
Base64 encode the resulting hash and add it to the request in the Security-Token header.
Example:
| Property | Data |
|---|---|
securityKey of the client (Base64) |
qGkfn2Ze7HltL+XiJNAT8S449mF8DbjHYP4GR3n0t6A= |
| requestMethod | POST |
| requestUrl | https://checkout-clients-sandbox-eu.qnips.com/api/v1/orders |
| timestampHeader | 2025-11-18T18:41:13Z |
| idempotencyKey | f0cdc088-02fc-46a1-8bfe-9c01df84e458 |
requestBody:
{
"startTimestamp": "2025-11-18T18:40:45Z",
"endTimestamp": "2025-11-18T18:41:12Z",
"orderTimestamp": "2025-11-18T18:41:12Z",
"profileToken": "BRBZU5RRXEVXGKHLBZR6",
"basketId": "c926d56f-f071-4511-a959-513099a9ff78",
"menuId": 514717,
"positions": [
{
"positionId": 0,
"productPlu": "QNI-1757944121588",
"quantity": 2
}
],
"consumptionMode": "Takeaway",
"totalGross": 990,
"currency": "EUR"
}
Generating the token:
Binary data is shown in Base64 representation in this example. Only the finished token needs to be Base64 converted to be written into the Security-Token header.
Input string:
"POST;https://checkout-clients-sandbox-eu.qnips.com/api/v1/orders;2025-11-18T18:41:13Z"
Input string UTF8 encoded:
UE9TVDtodHRwczovL2NoZWNrb3V0LWNsaWVudHMtc2FuZGJveC1ldS5xbmlwcy5jb20vYXBpL3YxL29yZGVyczsyMDI1LTExLTE4VDE4OjQxOjEzWg==
Idempotency-Key in binary:
8M3AiAL8RqGL/pwB34TkWA==
Encoded input concatenated with idempotency key:
UE9TVDtodHRwczovL2NoZWNrb3V0LWNsaWVudHMtc2FuZGJveC1ldS5xbmlwcy5jb20vYXBpL3YxL29yZGVyczsyMDI1LTExLTE4VDE4OjQxOjEzWvDNwIgC/Eahi/6cAd+E5Fg=
SHA256 hash of request body:
xvgl4JkVxrgNEgoKmhQPGekMKhrtOQcQpOMh4Eqmepg=
Input further concatenated with request body hash:
UE9TVDtodHRwczovL2NoZWNrb3V0LWNsaWVudHMtc2FuZGJveC1ldS5xbmlwcy5jb20vYXBpL3YxL29yZGVyczsyMDI1LTExLTE4VDE4OjQxOjEzWvDNwIgC/Eahi/6cAd+E5FjG+CXgmRXGuA0SCgqaFA8Z6QwqGu05BxCk4yHgSqZ6mA==
Full input HMACSHA256 hashed with the securityKey, final Security-Token to add as header:
Security-Token: oe60R+gVBgAxo2wqjZ8PXAwamT893buQyr9fOZy7tnY=
Payloads
The API uses JSON as payload format. All requests with a body must include the following headers:
Content-Type: application/json; charset=utf-8Accept: application/jsonFields that are not explicitily marked as
requiredare optional.
Currencies
The API expects amount currency values using the given denomination's smallest (minor) unit represented without decimals. For example:
1095to process 10.95EUR(or any other two-decimal currency).10to process 10JPY(or any other zero-decimal currency).
Make sure to use three-letter ISO 3166-1 alpha-3 codes as currency.
Dates & times
Timestamps:
All timestamps sent to or returned by the API must be in UTC.
All timestamps are formatted using the
ISO 8601standard:yyyy-MM-ddTHH:mm:ssZ. Example:2025-12-05T08:47:57Zmenio uses the time zone of the associated store to convert UTC timestamps to local timestamps.
Dates:
All dates are formatted using the ISO 8601 standard: yyyy-MM-dd. Example: 2025-12-05
Localization
Some endpoints support localized responses. Clients may specify their preferred language(s) using the Accept-Language header, however, this does not guarantee that the response will be localized. If no localization is available, the API will return the default language.
Responses
All API responses follow a consistent structure to ensure predictable parsing, error handling, and integration behavior.
Responses are returned in JSON format and encoded
UTF-8.A JSON schema is provided for each endpoint with a response body.
Clients should:
Not assume a field is always present
Handle
nullor missing values gracefullyFollow the schema for each API version
API responses are normal HTTP-responses with an HTTP status code, response headers and, if applicable, a response body.
The following HTTP status codes are used unless explicitly specified otherwise:
| Code | Description |
|---|---|
200 |
OK - Marks the successful execution. |
400 |
Bad Request - Request cannot be executed due to failed validations or unfulfilled preconditions. |
401 |
Unauthorized - Authorization and/or Security-Token header is not or incorrectly specified. |
500 |
Server error - Something went wrong during processing. |
[COMING SOON] Error response format:
{
"Error": {
"Reference": "123.754",
"Code": "unkown_error",
"Message": "Something unexpected happened"
}
}
Authorization
The API implements a layered authentication and authorization model designed to ensure secure client identification, controlled access to resources, and minimal exposure of long-term credentials. The mechanism is composed of three core components:
Client registration
Long-lived API keys
Short-lived access tokens
Clients must:
Implement appropriate storage mechanisms, rotation procedures, and renewal logic to maintain continuous authenticated access.
Client registration
All consuming applications must complete a client registration process prior to accessing the API. Clients have to be created in the menio Dashboard. After the intitial creation, the client is in a unregistered state and has to be activated by finalizing the registration through the API. Once a client is registred, the client can request long-lived API keys.
Long-lived API keys
Are used exclusively to obtain short-lived access tokens or rotate API keys and are not accepted for direct access to resource endpoints.
Expire in
60 daysand may be rotated or revoked at any time to maintain security standards.Must be securely stored and never be exposed or embedded in publicly accessible environments.
Short-lived access tokens
Are used to access resource endpoints.
Expire automatically after
10 minutes, reducing the impact of credential leakage or interception.Must be included in each request to resource endpoints via the
Authorizationheader.
Menus
The API provides access to menu cards and the products associated with them. These endpoints allow clients to retrieve available menus as well as drill down into the products offered within a specific menu for a specific day.
Baskets & Orders
A basket represents a collection of items selected during the checkout process. It serves as a temporary workspace where items, quantities and pricing information can be assembled before finalizing.
Items can be added, updated, or removed at any time while the basket is in an editable state.
Basket evaluation
Each time the basket is updated, the API recalculates any metadata, such as discounts, rewards, taxes and surcharges.
A basket may optionally be tied to a profile. When a profile token is provided, the API will return a personalized evaluation response.
A basket remains mutable until it is explicitly finalized.
Order
A basket can be finalized, by turning it into an order. Once finalized, the reward activation, invoicing and order processing flows get triggered.
Orders are no longer baskets and can not be re-evaluated.
Profiles
A profile is always linked to an end user (a consumer/customer) and can be either an app profile or a card profile.
A profile can be used to create personalized basket evaluation requests, link orders, or initiate balance transactions.
The API uses the profile's unique Token or an one-time password (OTP) for identification. These are provided and transmitted as reference or profileReference, depending on the context of the operation.
When an OTP is supplied, the API validates its authenticity, confirms its association with the intended profile, and checks its expiration before authorizing the request. This provides a secure, time-limited identification mechanism.
Profiles can be identified via a QR code presented in the app or through alternative identification methods at the point of sale.
Balance
Balance represents the amount of funds associated with a profile. This amount is safely stored in a personal digital wallet. The balance amount is mutable and changes based on approved transactions, such as top-ups, charges, refunds, etc.
A digital wallet is linked to a balance provider. The appropriate balance provider is automatically selected for the client based on the store where they are registered. Different stores may use different balance providers. The balance provider defines the applicable limits and validation rules.
An app profile may be linked to multiple card profiles. In that case, the sum of all balance in the digital wallets is available as balance for the requested profile.
Balance is always tied to one specific currency.
The currencies provided in the balance requests must match the profile's balance currency. Any request specifying a different
currencywill be rejected.All balance requests undergo multiple validation checks, including balance-limit and negative-balance validations. If any check fails, the request will be rejected.
Negative balance (overdraft) is not permitted.
Check-ins
A profile can use the menio app to scan a QR code or NFC tag to create a check-in within the menio system.
Check-ins are currently always associated with a physical tray, which is manually collected by the profile user to transport products or orders prior to checkout.
The API can return check-in information based on a provided tray ID. If a check-in exists for the specified tray ID, selected metadata of the associated profile is returned.
A check-in can be removed either manually by the profile via the menio app or automatically once the corresponding order has been successfully processed.