Skip to content
Coritan Docs

Idempotent requests

Send an Idempotency-Key header so that retrying a payment or an order does not charge you or order twice.

View as Markdown

Some requests must happen only once: a payment, an order, a new database. When the connection drops before the answer arrives, you cannot tell whether the request went through. Send a key with the request, and a retry with the same key answers what the first request did instead of doing it again.

  • Make a new random key for each operation you mean to happen once. A UUID fits every route on this page, and uuidgen prints one.
  • Send the same key, with the same body, on every retry of that operation.
  • Wait for an answer, or for your client to time out, before you retry.
  • Make a new key for a new operation, including a second try after a card is declined.
Shell
KEY=$(uuidgen)
curl -X POST https://api.coritan.com/api/v1/payments/invoices/5011/charge \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $KEY" \
  -d '{"payment_method_id": 812}'

To retry, run the same command with the same $KEY.

Route Where the key goes Format How long it counts
POST /payments/invoices/{invoice_id}/charge, and the older /pay Idempotency-Key header Up to 255 characters For as long as the payment attempt exists, with no expiry
POST /services/order for a floating IP idempotency_key in the body, required 1–64 letters, digits, dots, underscores, colons or hyphens Until the order fails, is cancelled or expires
POST /client/servers/{uuid}/databases Idempotency-Key header, or idempotency_key in the body Letters, digits, hyphens and underscores. Other characters are dropped, and only the first 64 count. Until the database is deleted
POST /chat/conversations and POST /chat/conversations/{conversation_id}/messages client_request_id in the body Up to 64 characters For as long as the conversation or the message exists
POST /orgs/{org_slug}/storefront/order Idempotency-Key header Only the first 128 characters count No expiry
POST /orgs/{org_slug}/portal/services/{service_id}/change-plan Idempotency-Key header Only the first 128 characters count While its answer still describes the service
POST /orgs/{org_slug}/portal/ips/order idempotency_key in the body, required 1–64 letters, digits, dots, underscores, colons or hyphens Until the order fails, is cancelled or expires
POST /orgs/{org_slug}/portal/servers/{uuid}/databases and POST /orgs/{org_slug}/staff/servers/{uuid}/databases Idempotency-Key header, or idempotency_key in the body Up to 64 characters Until the database is deleted
POST /orgs/{org_slug}/store/carts/{cart_id}/complete Idempotency-Key header Up to 128 characters. A longer key answers 422. 24 hours
Payments
The first payment attempt as it is now, with the same id. Nothing is charged a second time. Once that payment has paid the whole invoice, a repeat answers 400 with No remaining balance on invoice instead, so read the invoice to confirm it is paid. A declined attempt stays declined under its key: send a new key to try again.
Floating IP orders
The first order. POST /services/order sets message to Order already submitted within two minutes of the first request, and to Replayed existing IP order once the order has an invoice. POST /orgs/{org_slug}/portal/ips/order adds "replay": true. Order a floating IP describes the order and its statuses.
Databases
The database the first request created on that server, with its password. When the first request stopped part way, the repeat finishes creating it.
Support conversations and messages
The conversation or the message the first request created.
Storefront orders
The answer the first request received.
Plan changes
The answer the first request received, while it still describes the service: an upgrade whose invoice is still waiting to be paid, or a change to the plan the service is still on. Otherwise the request runs again, so a key you send after moving to another plan asks for the change again.
Store API cart completion
The status and the body the first request received. Completing a cart that already has its order answers that order again, with or without a key.

When the first request answered an error, a retry with the same key runs the request again.

Status Answer What it means
409 An identical IP order is already in progress; retry in a moment The first floating IP order with this key is still running. Wait a moment and send it again.
409 Order already in progress The first storefront order with this key is still running.
409 Plan change already in progress The first plan change with this key is still running.
409 "error": "idempotency_in_progress" The first cart completion with this key is still running.
409 "error": "idempotency_key_reused" and This Idempotency-Key was used for a different request. The key was used to complete another cart. Make a new key.
409 "error": "database_busy" and That database is being deleted The database this key created is being deleted. Make a new key.
422 idempotency_key is required for IP orders A floating IP order was sent without a key.
422 A message that starts idempotency_key must be The key has a character or a length a floating IP order does not accept.

Make a new key for each different storefront order or plan change. A key sent again with a different product, plan, hostname or config fails.

POST /services/order also catches a repeat that carries no key. An order for the same product, price and hostname as one you placed in the last two minutes answers that first order, with message set to Order already submitted, while the first is still pending. This holds for every product, and for a floating IP order whatever key it sends. Other products accept idempotency_key and ignore it. To order two services on the same plan at once, give each its own hostname. Order a service describes the order and its answer.

POST /orgs/{org_slug}/storefront/order does the same for an organization's customers, with or without a key, and marks the answer "replayed": true.

Other routes take no key, and a repeat is a new request. Before you retry one whose answer you did not receive, read the record it changes: list your invoices to see whether a payment went through, or your services to see whether an order arrived.

The customer portal's POST /orgs/{org_slug}/portal/invoices/{invoice_id}/charge takes no key. Once the invoice is paid, it answers 404 with Invoice not found or already paid.