DocumentationPOST Refund a payment
Payments API
POST
/payments/{id}/refundsRefund a payment
Full or partial. Omit `amount` to refund everything still refundable.
Use your sandbox environment to start. Understand error codes and payment statuses before handling a live payment.
Refund a payment
curl --request POST "https://api.veyqo.org/api/v1/payments/$PAYMENT_ID/refunds" \
--header "Authorization: Bearer $VEYQO_SECRET_KEY" \
--header "Accept: application/json" \
--header "Idempotency-Key: $OPERATION_IDEMPOTENCY_KEY" \
--header "Content-Type: application/json" \
--data '{
"amount": 25000,
"reason": "requested_by_customer"
}'{
"success": true,
"data": {
"id": "ref_01M6EB66SC61Q3RQYAN0693DGM",
"object": "refund",
"payment": "pay_01M6EB66SC61Q3RQYAN0693DGM",
"amount": 25000,
"currency": "NGN",
"status": "pending",
"reason": "requested_by_customer",
"failure_message": 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/payments/{id}/refunds
Server secret key required. Scope: refunds: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.
Path and query parameters
| Parameter | Location | Required | Description |
|---|---|---|---|
| id | path | Yes | Veyqo payment ID or URL-encoded merchant reference. Prefer the Veyqo ID for unambiguous lookup. |
Request body
amountintegeroptional- Omit this property to refund the entire remaining refundable amount. Do not send null. Minimum 1.
reasonstring | nulloptional- Reason for the refund. Maximum 255 characters.
Response fields
idstringrequired- Veyqo refund ID.
object"refund"required- See the JSON example.
paymentstringrequired- Original Veyqo payment ID.
amountintegerrequired- Refund amount in the smallest currency unit.
currencystringrequired- Original payment currency.
statusstringrequired- Values: pending, succeeded, failed.
reasonstring | nullrequired- Optional reason.
failure_messagestring | nullrequired- Provider failure message when available.
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. |
| PAYMENT_NOT_FOUND | 404 | Use the saved Veyqo payment ID or correctly URL-encoded merchant reference with the original project’s key. | No blind retry. |
| ENVIRONMENT_MISMATCH | 403 | Use the correct sandbox/live key. Resources outside the key’s project remain not-found instead of disclosing ownership. | After selecting the correct key. |
| 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. |
| PAYMENT_ALREADY_REFUNDED | 409 | Read the payment and refunds, compare amount_refunded to amount, and avoid issuing a duplicate refund. | No. |
| INVALID_PROVIDER | 422 | Choose a supported connected provider. Refund/direct-checkout capabilities can differ from simple payment creation. | After configuration or provider selection changes. |
| PROVIDER_AUTHENTICATION_FAILED | 502 | The merchant must check/rotate the provider credentials in the dashboard. Do not expose those secrets to your application users. | After credential correction; reconcile existing payment first. |
| PROVIDER_UNAVAILABLE | 503 | Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. | Conditional: reconcile unknown outcomes first. |
| PROVIDER_REQUEST_FAILED | 422 | Read the safe message, inspect the payment’s failure details and correct the request or provider account. Never repeatedly retry a business rejection. | Only after resolving the cause. |
| 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. |