DocumentationPOST Create a checkout session
Checkout API
POST
/checkout/sessionsCreate a checkout session
Returns a checkout `url` where the customer pays without leaving Veyqo: by bank transfer, USSD or mobile money on the page itself, or by card in the gateway's own secure form over it. Created here with your secret key, the amount cannot be changed by the customer; open it with the JS SDK or redirect to `url`.
Use your sandbox environment to start. Understand error codes and payment statuses before handling a live payment.
Create a checkout session
curl --request POST "https://api.veyqo.org/api/v1/checkout/sessions" \
--header "Authorization: Bearer $VEYQO_SECRET_KEY" \
--header "Accept: application/json" \
--header "Idempotency-Key: $OPERATION_IDEMPOTENCY_KEY" \
--header "Content-Type: application/json" \
--data '{
"amount": 50000,
"currency": "NGN",
"reference": "ORDER-1001",
"provider": "paystack",
"customer": {
"email": "customer@example.com"
},
"success_url": "https://shop.example.com/thanks",
"cancel_url": "https://shop.example.com/cart"
}'{
"success": true,
"data": {
"id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
"object": "checkout_session",
"url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
"status": "open",
"source": "api",
"provider": "paystack",
"amount": 50000,
"currency": "NGN",
"reference": "ORDER-1001",
"description": "Order 1001",
"customer_email": "customer@example.com",
"payment": null,
"success_url": "https://shop.example.com/thanks",
"cancel_url": "https://shop.example.com/cart",
"expires_at": "2026-11-02T13:00:00+00:00",
"completed_at": null,
"created_at": "2026-11-02T12:00:00+00:00"
}
}Illustrative examples. Replace IDs and environment variables with your own values. Keep secret keys on your server.
Headers
Authorizationstringrequired- Bearer <secret-key>. This key determines your project environment and must stay on your server.
Content-Typestringrequired- application/json
Acceptstringoptional- application/json
Idempotency-Keystringoptional- Persist one key for the operation and reuse it with the unchanged body on retries. Maximum 255 characters.
Endpoint
POST https://api.veyqo.org/api/v1/checkout/sessions
Server secret key required. Scope: payments:write. The key determines the project and environment; no project-selection header is accepted.
For each new operation, generate and persist one OPERATION_IDEMPOTENCY_KEY. Retry the unchanged request with that same key. Do not generate a new key on every retry.
Request body
amountintegerrequired- Integer minor-unit amount. NGN 500.00 is 50000; JPY 500 is 500. Minimum 1.
currencystringrequired- Three-letter currency supported by the selected provider. Maximum 3 characters.
referencestring | nulloptional- Order reference; a session can create multiple uniquely referenced payment attempts. Maximum 100 characters.
descriptionstring | nulloptional- Maximum 500 characters.
customerobjectoptional- See the JSON example.
customer.emailstring | nulloptional- Maximum 255 characters. Format: email.
customer.namestring | nulloptional- Maximum 255 characters.
metadataobject | array | nulloptional- Your non-sensitive JSON metadata. Objects are recommended; do not store secrets or card details. Maximum 20 entries.
providerstring | nulloptional- Gateway selected by your server or project default; the customer chooses a payment method, not the gateway. Maximum 40 characters.
success_urlstring | nulloptional- HTTP or HTTPS return URL. Use HTTPS in production. Maximum 2048 characters. Format: uri.
cancel_urlstring | nulloptional- HTTP or HTTPS cancellation URL. Use HTTPS in production. Maximum 2048 characters. Format: uri.
Response fields
idstringrequired- Checkout session ID (cs_ prefix).
object"checkout_session"required- See the JSON example.
urlstringrequired- Hosted Veyqo URL; redirect here or open this session using VeyqoCheckout. Format: uri.
statusstringrequired- Values: open, completed, expired.
sourcestringrequired- Values: api, browser, link.
providerstringrequired- Selected provider slug; this field is an object on the browser session detail endpoint.
amountintegerrequired- Server-defined amount in minor units.
currencystringrequired- Three-letter currency.
referencestring | nullrequired- Your order reference, when supplied.
descriptionstring | nullrequired- Checkout description.
customer_emailstring | nullrequired- Customer email if already supplied.
paymentobject | nullrequired- Current payment attempt, if any. A session can have multiple attempts over time.
success_urlstring | nullrequired- Configured return URL. A redirect is not proof of payment.
cancel_urlstring | nullrequired- Configured cancellation URL.
expires_atstringrequired- Session expiry time. Format: date-time.
completed_atstring | nullrequired- ISO 8601 timestamp. Format: date-time.
created_atstring | nullrequired- ISO 8601 timestamp. Format: date-time.
Errors and recovery
| Code | HTTP | Recovery | Retry policy |
|---|---|---|---|
| INVALID_API_KEY | 401 | Use a current kc_test_ or kc_live_ secret key on /api/v1. Use a pk_test_ or pk_live_ publishable key only on browser checkout. | After fixing credentials. |
| INSUFFICIENT_PERMISSION | 403 | Grant the required scope or use a suitably scoped key. Dashboard organization roles and staff permissions are separate. | After permission changes. |
| RATE_LIMIT_EXCEEDED | 429 | Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. | Yes, after Retry-After; preserve write idempotency. |
| METHOD_NOT_ALLOWED | 405 | Use the method documented for the endpoint, such as POST for verification and refunds. | After fixing the method. |
| INTERNAL_ERROR | 500 | Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. | Safe reads: bounded backoff. Writes: reconcile first. |
| VALIDATION_FAILED | 422 | Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. | No automatic retry. |
| IDEMPOTENCY_KEY_REUSED | 409 | Reuse the exact original request to recover that operation, or use a new key only for a genuinely different operation. | Do not retry a changed body with that key. |
| IDEMPOTENCY_IN_PROGRESS | 409 | Wait briefly, retry with the same key and unchanged request, then reconcile by reference if the result remains uncertain. | Back off with jitter; preserve key/body. |
| PLAN_LIMIT_REACHED | 402 | Review the active plan, project/usage allowances and billing status with the organization owner. | After resolving plan/billing restrictions. |