Accept payments
Create & verify payments
Initialize a charge, direct the customer to checkout, and confirm what happened.
Create on your server
POST /payments starts a payment through a connected provider. The provider field selects a provider; its connection must belong to the key’s environment. Calculate the amount from trusted order data.
curl https://api.veyqo.org/api/v1/payments \
-H "Authorization: Bearer $VEYQO_SECRET_KEY" \
-H "Idempotency-Key: $ORDER_PAYMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "NGN",
"reference": "ORDER-1001",
"provider": "paystack",
"customer": { "email": "customer@example.com" },
"metadata": { "order_id": "1001" }
}'Payment request fields
| Field | Meaning |
|---|---|
| amount | Required positive integer in the smallest currency unit. |
| currency | Required three-letter currency code, supported by the provider. |
| customer.email | Required customer email for the nested customer form. |
| reference | Your order reference; if omitted, the payment ID becomes the reference. |
| provider | Provider slug, such as paystack. |
| callback_url | Optional HTTPS URL the provider can return the customer to. |
| metadata | Optional application context, such as an internal order ID. |
Retry the same operation safely
Send an Idempotency-Key on POST requests. Generate and persist it before the first attempt. If the request times out, retry with the same key and exactly the same body. A different body with the same key returns a conflict.
Use a new key for a new logical operation. Your order reference and idempotency key serve different purposes: one identifies the order; the other identifies a request attempt across retries.
Verify before fulfilment
GET /payments/{id} retrieves the stored payment. POST /payments/{id}/verify queries the provider and updates the payment result. Both require payments:read.
Pending is not a successful payment. Store the payment ID and reconcile webhooks against the order’s reference, expected amount and currency. Deduplicate fulfilment even if the same confirmation arrives more than once.
Read the real payment response
POST /payments returns HTTP 201 with a payment in data. Its checkout address is data.checkout_url. It is not data.checkout.url, and its initial status is usually pending. The provider URL in the example is illustrative.
{
"success": true,
"data": {
"id": "pay_01M6EB66SC61Q3RQYAN0693DGM",
"object": "payment",
"reference": "ORDER-1001",
"status": "pending",
"amount": 50000,
"amount_refunded": 0,
"currency": "NGN",
"customer": {
"email": "customer@example.com",
"name": "Ada Lovelace",
"phone": null
},
"description": "Order 1001",
"checkout_url": "https://checkout.paystack.com/example",
"provider": "paystack",
"provider_reference": "provider_reference_example",
"metadata": {
"order_id": "1001"
},
"failure_code": null,
"failure_message": null,
"authorized_at": null,
"succeeded_at": null,
"failed_at": null,
"created_at": "2026-11-02T12:00:00+00:00"
}
}Keep the payment ID and merchant reference
Persist the Veyqo payment ID alongside your order before redirecting the customer. GET /payments/{id} and POST /payments/{id}/verify accept either that ID or your URL-encoded reference directly in the path. There is no ?reference= lookup on the single-payment endpoint.
Use the Veyqo ID for unambiguous reconciliation, especially when order references are reused across sandbox and live. Cross-project resources stay not-found; a known payment in the other environment of the same project can produce ENVIRONMENT_MISMATCH.
Payment states
| Status | Meaning / action |
|---|---|
| created | Recorded by Veyqo before a provider result. Do not fulfil. |
| pending | Waiting for the customer or provider. Do not fulfil. |
| processing | Provider outcome is not settled yet. Verify later. |
| succeeded | Payment confirmed. Compare amount, currency and order ownership before fulfilling once. |
| failed | Payment failed. Inspect failure_code and failure_message. |
| cancelled | Payment was cancelled. Do not fulfil. |
| partially_refunded | Some captured funds have been refunded. Track amount_refunded. |
| refunded | The captured payment has been fully refunded. |
API failures and payment failures are different
An error envelope with success:false describes a rejected or failed API operation. A 200 response can return a payment whose status is failed, and a 201 response can return a pending payment. Inspect both layers. Payment failure_code is not the same catalogue as error.code.
gateway_declined means the provider rejected the payment; show an appropriate customer message and let the customer choose another method. amount_mismatch means the provider-reported amount failed reconciliation; do not fulfil, do not override it from browser data, and investigate the stored order and provider transaction. A creation failure can store the corresponding API error code on the payment. failure_message contains provider-specific detail and may be null; do not use its wording as a stable machine code.