Docs
For agents
The contract for creating a payment. Use only the fields on this page. Do not invent parameters, and do not treat the browser redirect as payment.
Create a payment
One request. Send the payer to url. Amounts are integers in the currency's smallest unit: 2500 with usd is 25.00.
curl https://cortanapay.com/api/v1/checkout/sessions \
-H "Authorization: Bearer ck_test_YOUR_KEY" \
-H "Idempotency-Key: order-1042" \
-H "Content-Type: application/json" \
-d '{"amount":2500,"currency":"usd","description":"Order 1042"}'- Authorization
Bearer ck_test_…orBearer ck_live_…. The key chooses the mode. There is no mode field.- Idempotency-Key
- Required on create. 8 to 255 characters. Same key and same body returns the same session. Same key and a different body is 409.
- amount
- Required integer, at least 1. Minor units.
- currency
- Required. Three-letter ISO code, stored lowercase.
- description
- Optional. Shown on the payment page. Not sent to the payment account unless the merchant turns that on.
- customer.email, customer.name
- Optional. Crypto checkout needs an email; if you omit it, Cortana sends [email protected] on that checkout only.
- external_id
- Optional. Your id. Unique in the workspace.
- metadata
- Optional. Up to 20 string pairs. Stored on the invoice and echoed in callbacks. Not sent to the payment account by default.
- template
- Optional. split, compact, or classic.
- callback_url
- Optional https URL. Must already be an enabled webhook endpoint in the same mode.
- success_url, cancel_url
- Optional public https URLs. The payer may be sent there. They do not mean the payment succeeded.
- expires_in_minutes
- Optional. 5 to 43200. Default 10080 (7 days).
- allowed_providers
- Optional. Omit to offer every connected account. Values: stripe, whop, payerurl, manual. mock is test only.
Decide paid
Paid is payment_status equal to paid on GET /api/v1/checkout/sessions/:id, or a callback whose signature you verified with type invoice.paid. A redirect, a 201, or the payer saying they paid is not enough.
- GET /api/v1/checkout/sessions/:id
- Same object as create. payment_status is unpaid or paid.
- GET /api/v1/invoices/:id
- The invoice. payment_url is the same page as session.url.
- POST /api/v1/invoices
- Line items instead of one amount. Same auth and idempotency rules. See the JSON API page.
- POST …/void and …/expire
- Stop an open invoice or session. Do not call these after it is paid.
Signature
Cortana-Signature is t=<seconds>,v1=<hex hmac> over the raw body.Do not
- Send card numbers, CVCs, or bank secrets
- The payer types those on the payment page or the provider's page.
- Add fields that are not listed
- Unknown fields are rejected.
- Retry a create without the same Idempotency-Key
- A timeout can otherwise create a second invoice.
- Use a test key against a live object, or the reverse
- The key's mode is the only mode it can see.
- Mark your order paid from success_url
- Fetch the session or verify the callback.
Errors to handle
Body shape is { "error": { "code", "message" } }. Match code.
- invalid_api_key
- 401. The key is missing, wrong, or revoked.
- live_access_required
- 403. This workspace cannot take live payments yet. Use a test key.
- idempotency_key_required
- 400. Send Idempotency-Key.
- idempotency_conflict
- 409. You reused a key with a different body. Use a new key.
- request_in_progress
- 409. The first call with this key is still running. Retry the same request.
- rate_limited
- 429. Wait the Retry-After seconds.
More status codes are on the reference. Routing and caps are on payment methods.
Company setup is email
Pages under /services are inquiries, not API calls. Do not create an invoice for them. The offers are a US company, tax numbers, a business address, and bank or payment-account applications. Write to [email protected]. The fee and the timing are in the reply. Taking payments still uses the checkout call above, and only after the merchant has connected an account.