API referencepayments
Add payment method
POST
/v1/payments/methodsIdempotency-Key requiredAccepts bearer
Save a card (as a PSP token) or a UPI method
kind CARD takes token, a payment-method token the client obtained from the PSP's hosted fields; kind UPI takes vpa.Show more
kind CARD takes token, a payment-method token the client obtained from the PSP's hosted fields; kind UPI takes vpa. A card number, security code or any card-number-shaped value is refused 400 VALIDATION details.reason INSTRUMENT_DATA_REFUSED and nothing is stored. The token is verified with the PSP before it is saved; a declined token is 402 PAYMENT_FAILED details.reason CARD_DECLINED (details.declineCode) and nothing is saved. The first method saved becomes the default. With the money model CARD (POST /v1/activation/money-model) rail step money_model is done once one method is saved. brand and last4 are derived by the server from the PSP token, never sent by the client. Human session only; Owner only, as the money model (403 PERMISSION_DENIED details.reason OWNER_ONLY). Idempotency-Key required: a replay returns the original method and saves nothing twice. Audited (payments.method_added, never the token). the card provider and the UPI provider are deployment settings (aikonic.payment-methods.card-provider harness or stripe; aikonic.payment-methods.upi-provider harness or razorpay; harness on DEV and SANDBOX only). With the card provider stripe the client first calls POST /v1/payments/methods:setup, confirms the card with the card provider's browser library (its hosted card fields: the card number never reaches Apiq) and then sends kind CARD with token the card provider's payment-method id (pm_ followed by the id) the confirmed setup carries; the server retrieves it from the card provider, takes brand and last4 from it, keeps it attached to the tenant's own customer at the card provider and stores the id only. A payment method the card provider does not know, or one attached to another customer, is 400 VALIDATION details.field token. With the UPI provider razorpay the vpa is validated with the provider before it is saved; a VPA the provider says does not exist or cannot receive is 400 VALIDATION details.reason VPA_INVALID (details.field vpa) and nothing is saved. A provider that cannot be reached is 502 UPSTREAM_UNAVAILABLE (retryable, nothing saved).Headers
- Idempotency-KeystringRequired
Mandatory on mutations: **48h TTL**; replay with same body-hash returns the original response with Idempotency-Replayed true; same key + different body is 409 IDEMPOTENCY_CONFLICT; in-flight duplicate…Show more
Mandatory on mutations: **48h TTL**; replay with same body-hash returns the original response with Idempotency-Replayed true; same key + different body is 409 IDEMPOTENCY_CONFLICT; in-flight duplicate is 409 IDEMPOTENCY_IN_PROGRESS.
Request body
- kindstringRequired
- CARD
- UPI
- tokenstringOptional
kind CARD — the PSP payment-method token; the harness PSP's test tokens are tok_harness_success and tok_harness_decline.Show more
kind CARD — the PSP payment-method token; the harness PSP's test tokens are tok_harness_success and tok_harness_decline. round 3 (amended 2026-10-29): when the setup provider is STRIPE (POST /v1/payments/methods:setup), the card provider's payment-method id (pm_ followed by the id) that its browser library confirmed on the setup; never card data. - vpastringOptional
kind UPI — the virtual payment address; stored for the PSP, answered only masked.Show more
kind UPI — the virtual payment address; stored for the PSP, answered only masked. round 3 (amended 2026-10-29): with the UPI provider razorpay it is validated with the provider before it is saved; an address the provider refuses is 400 VALIDATION details.reason VPA_INVALID.
Responses
- 201The saved methodSavedPaymentMethod
- 400VALIDATION — a missing or malformed member, or card data instead of a token (INSTRUMENT_DATA_REFUSED)ApiErrorResponse
- 401ApiErrorResponse
UNAUTHENTICATED — missing or expired token.Show more
UNAUTHENTICATED — missing or expired token. Declared on every operation because `security` is declared globally at the document root: every route is authenticated, so every route can answer 401. - 402PAYMENT_FAILED CARD_DECLINED — the PSP declined the card when it was verified; nothing is savedApiErrorResponse
- 403ApiErrorResponse
- 405ApiErrorResponse
VALIDATION — the public edge serves GET, POST, PUT, PATCH and DELETE only; any other method is refused before the platform sees it (details.reason METHOD_NOT_ALLOWED, details.source edge).Show more
VALIDATION — the public edge serves GET, POST, PUT, PATCH and DELETE only; any other method is refused before the platform sees it (details.reason METHOD_NOT_ALLOWED, details.source edge). Not retryable as sent. - 409IDEMPOTENCY_CONFLICT | IDEMPOTENCY_IN_PROGRESS — the only 409s of a mutation with no domain conflictApiErrorResponse
- 413ApiErrorResponse
VALIDATION — the request body is larger than the surface's limit.Show more
VALIDATION — the request body is larger than the surface's limit. Not retryable as sent: shrink the body. Declared on every operation that takes a request body. details carries exactly one key, maxBodyBytes (integer): the limit that applies to this surface, in bytes. - 414ApiErrorResponse
VALIDATION — the request URI (path and query string) is longer than 8 KiB; the public edge refuses it before the platform sees it (details.reason URI_TOO_LONG, details.source edge).Show more
VALIDATION — the request URI (path and query string) is longer than 8 KiB; the public edge refuses it before the platform sees it (details.reason URI_TOO_LONG, details.source edge). Not retryable as sent: send long input in the body of a POST. - 415ApiErrorResponse
VALIDATION — a request body that is not JSON (application/json or application/*+json; a form body only on the OAuth token routes).Show more
VALIDATION — a request body that is not JSON (application/json or application/*+json; a form body only on the OAuth token routes). The public edge refuses it before the platform sees it (details.reason UNSUPPORTED_MEDIA_TYPE, details.source edge). Not retryable as sent: send Content-Type application/json. Declared on every operation that takes a JSON request body. - 500INTERNAL — a bug, and traceId is the support handle.ApiErrorResponse
- 501ApiErrorResponse
NOT_IMPLEMENTED PAYMENT_METHODS_UNAVAILABLE — saved payment methods are off on this deployment (aikonic.payment-methods.enabled, off by default, on at DEV and SANDBOX).Show more
NOT_IMPLEMENTED PAYMENT_METHODS_UNAVAILABLE — saved payment methods are off on this deployment (aikonic.payment-methods.enabled, off by default, on at DEV and SANDBOX). Not retryable. - 502Retryable; details.psp names the provider.ApiErrorResponse
Errors you should handle
Branch on code and honour retryable — never on the HTTP status alone.
| 400 | VALIDATION A card is saved as a PSP token; token is required when kind is CARD. | not retryable |
| 401 | UNAUTHENTICATED The bearer token is expired. Re-authenticate and retry. | not retryable |
| 402 | PAYMENT_FAILED The card was declined. Try another card. | not retryable |
| 403 | PERMISSION_DENIED Reading wallets needs the finance:read permission. | not retryable |
| 405 | VALIDATION This method is not served. | not retryable |
| 409 | IDEMPOTENCY_CONFLICT Idempotency-Key 7f0c33d1-9a1e-4d2c-9f77-1c0f2b3a4d55 was used with a different body; never executed | not retryable |
| 409 | IDEMPOTENCY_IN_PROGRESS A request with this Idempotency-Key is still executing | retryable |
| 413 | VALIDATION The request body is larger than this API accepts (262144 bytes). | not retryable |
| 414 | VALIDATION The request URI is longer than 8 KiB. | not retryable |
| 415 | VALIDATION Send application/json. | not retryable |
| 500 | INTERNAL An unexpected error occurred. Quote the traceId to support. | retryable |
| 501 | NOT_IMPLEMENTED Saved payment methods are not available on this deployment. | not retryable |
| 502 | UPSTREAM_UNAVAILABLE The payment provider is not answering right now. Try again in a minute. | retryable |