Idempotent requests
Send an Idempotency-Key header so that retrying a payment or an order does not charge you or order twice.
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.
Send a key
Section titled Send a key- Make a new random key for each operation you mean to happen once. A UUID fits every route on this page, and
uuidgenprints 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.
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.
Routes that take a key
Section titled Routes that take a 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 |
What a repeat answers
Section titled What a repeat answers- 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 answers400withNo remaining balance on invoiceinstead, 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/ordersetsmessagetoOrder already submittedwithin two minutes of the first request, and toReplayed existing IP orderonce the order has an invoice.POST /orgs/{org_slug}/portal/ips/orderadds"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.
Errors
Section titled Errors| 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.
Repeated orders without a key
Section titled Repeated orders without a keyPOST /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.
Routes without a key
Section titled Routes without a keyOther 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.