Skip to content
ApiqDevelopers
API v1.64.0Open console
API referencepayments

Add payment method

POST/v1/payments/methods
Idempotency-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 morekind 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 moreMandatory 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 morekind 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 morekind 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
  • 401
    UNAUTHENTICATED — missing or expired token.Show moreUNAUTHENTICATED — 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.
    ApiErrorResponse
  • 402PAYMENT_FAILED CARD_DECLINED — the PSP declined the card when it was verified; nothing is savedApiErrorResponse
  • 403ApiErrorResponse
  • 405
    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 moreVALIDATION — 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.
    ApiErrorResponse
  • 409IDEMPOTENCY_CONFLICT | IDEMPOTENCY_IN_PROGRESS — the only 409s of a mutation with no domain conflictApiErrorResponse
  • 413
    VALIDATION — the request body is larger than the surface's limit.Show moreVALIDATION — 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.
    ApiErrorResponse
  • 414
    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 moreVALIDATION — 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.
    ApiErrorResponse
  • 415
    VALIDATION — a request body that is not JSON (application/json or application/*+json; a form body only on the OAuth token routes).Show moreVALIDATION — 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.
    ApiErrorResponse
  • 500INTERNAL — a bug, and traceId is the support handle.ApiErrorResponse
  • 501
    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 moreNOT_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.
    ApiErrorResponse
  • 502Retryable; details.psp names the provider.ApiErrorResponse

Errors you should handle

Branch on code and honour retryable — never on the HTTP status alone.

400VALIDATION
A card is saved as a PSP token; token is required when kind is CARD.
not retryable
401UNAUTHENTICATED
The bearer token is expired. Re-authenticate and retry.
not retryable
402PAYMENT_FAILED
The card was declined. Try another card.
not retryable
403PERMISSION_DENIED
Reading wallets needs the finance:read permission.
not retryable
405VALIDATION
This method is not served.
not retryable
409IDEMPOTENCY_CONFLICT
Idempotency-Key 7f0c33d1-9a1e-4d2c-9f77-1c0f2b3a4d55 was used with a different body; never executed
not retryable
409IDEMPOTENCY_IN_PROGRESS
A request with this Idempotency-Key is still executing
retryable
413VALIDATION
The request body is larger than this API accepts (262144 bytes).
not retryable
414VALIDATION
The request URI is longer than 8 KiB.
not retryable
415VALIDATION
Send application/json.
not retryable
500INTERNAL
An unexpected error occurred. Quote the traceId to support.
retryable
501NOT_IMPLEMENTED
Saved payment methods are not available on this deployment.
not retryable
502UPSTREAM_UNAVAILABLE
The payment provider is not answering right now. Try again in a minute.
retryable