Orders
Place an order for an instant server, paid from your account credit, and follow your orders until the server is ready. Reading needs read; ordering needs order. For a step-by-step walk-through see the Ordering guide.
Place an order
POST /orders orders one instant server. It is paid from the account's credit at once; there is no card or invoice step. Needs an Idempotency-Key (except for a dry run).
| Body field | Required | Rule |
|---|---|---|
offer_id | yes | An offer id from Offers, such as "ofr_12". |
billing_cycle | yes | "monthly". No other cycle can be ordered through the API. |
os_id | yes | One of the offer's os ids, such as "os_31". |
ssh_key_id | no | A saved key from SSH keys, such as "sshkey_7". It is installed on the server. |
label | no | 1 to 60 characters: letters, digits, spaces, ., -, _. Set as the server's label once it is paid. |
expected_total | yes, except in a dry run | {"amount": "15480", "currency": "USD"}. The total you expect to pay: amount in minor units (cents) as a string of digits, currency as three capital letters. Take it from a dry run. |
Any other field, a field of the wrong type, or a name given twice is 400 invalid_body. The configuration is always the offer's default one with your chosen OS. Quantity is one server per order.
Dry run
Add ?dry_run=true to see the exact total and check the order would go through. Nothing is ordered, reserved or charged. No Idempotency-Key is needed, and expected_total may be left out.
curl -sS -X POST "https://api.redswitches.com/v1/orders?dry_run=true" \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"offer_id":"ofr_12","billing_cycle":"monthly","os_id":"os_31","ssh_key_id":"sshkey_7"}'const quote = await rs.orders.create(
{ offer_id: "ofr_12", billing_cycle: "monthly", os_id: "os_31", ssh_key_id: "sshkey_7" },
{ dryRun: true },
);quote = client.orders.create(
offer_id="ofr_12", billing_cycle="monthly", os_id="os_31", ssh_key_id="sshkey_7", dry_run=True
)quote, err := client.Orders.Create(ctx, &redswitches.OrderCreateRequest{
OfferID: "ofr_12", BillingCycle: "monthly", OSID: "os_31", SSHKeyID: "sshkey_7",
}, &redswitches.OrderOptions{DryRun: true}){
"dry_run": true,
"offer_id": "ofr_12",
"billing_cycle": "monthly",
"total": { "amount": "15480", "currency": "USD" },
"recurring": { "amount": "12900", "currency": "USD" },
"paid_from_credit": { "amount": "15480", "currency": "USD" }
}
The answer is 200. total is the first payment including setup and tax; recurring is the monthly renewal amount before tax. Both are minor units. A dry run runs the same checks as a real order (stock, limits, credit), so it fails with the same errors.
Order
Send the same body with expected_total set to the dry run's total:
curl -sS -X POST https://api.redswitches.com/v1/orders \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-web-1-2026-11-15" \
-d '{"offer_id":"ofr_12","billing_cycle":"monthly","os_id":"os_31","ssh_key_id":"sshkey_7","label":"web-1","expected_total":{"amount":"15480","currency":"USD"}}'const order = await rs.orders.create(
{
offer_id: "ofr_12",
billing_cycle: "monthly",
os_id: "os_31",
ssh_key_id: "sshkey_7",
label: "web-1",
expected_total: quote.total,
},
{ idempotencyKey: "order-web-1-2026-11-15" },
);order = client.orders.create(
offer_id="ofr_12",
billing_cycle="monthly",
os_id="os_31",
ssh_key_id="sshkey_7",
label="web-1",
expected_total=quote.total,
idempotency_key="order-web-1-2026-11-15",
)order, err := client.Orders.Create(ctx, &redswitches.OrderCreateRequest{
OfferID: "ofr_12", BillingCycle: "monthly", OSID: "os_31", SSHKeyID: "sshkey_7", Label: "web-1",
ExpectedTotal: quote.Total,
}, &redswitches.OrderOptions{IdempotencyKey: "order-web-1-2026-11-15"}){
"id": "ord_456",
"invoice_id": "inv_789",
"server_ids": ["srv_123"],
"status": "paid",
"delivery": "queued",
"billing_cycle": "monthly",
"total": { "amount": "15480", "currency": "USD" },
"recurring": { "amount": "12900", "currency": "USD" },
"paid_from_credit": { "amount": "15480", "currency": "USD" },
"poll_after": 30
}
The answer is 201 Created: the order exists and is paid. Delivery starts on its own. Follow it with GET /orders/{id}.
The root password never appears in the API. The welcome email with the login details goes to the account owner, as for any order.
Order errors
| Status | Code | What to do |
|---|---|---|
| 402 | insufficient_credit | details.needed is the credit missing (minor units). Add funds in the client area. |
| 403 | ordering_not_enabled | The owner turns ordering on in Settings → API. |
| 403 | cooling_off | Ordering opens 24 hours after it was turned on and after a new ordering key. Wait details.retry_after seconds. |
| 403 | not_eligible | The account may not order now. The owner sees why on the API page. |
| 403 | cap_reached | details.cap names the limit, details.limit its value and details.window its window. Account limits are set by RedSwitches: contact support to raise one. See the Ordering guide. |
| 403 | ordering_paused | RedSwitches paused API ordering. Try later. |
| 409 | price_changed | details.total is the current total. Check it, then order again with a new Idempotency-Key and the new expected_total. |
| 409 | sold_out | Pick another offer. |
| 409 | order_not_placed | Nothing was created or charged. Staff have been told. |
| 409 | order_under_review | The order exists but needs a staff check before it is paid or delivered. details.order is its id. Do not order again. |
| 409 | in_progress | The same Idempotency-Key is still running. Ask again after details.retry_after seconds with the same key. |
| 422 | not_orderable | The offer, OS, SSH key or billing cycle cannot be ordered through the API. |
| 422 | idempotency_conflict | The Idempotency-Key was used with another body. |
If an order times out, send exactly the same request again with the same Idempotency-Key. You get the original result; you never get a second server. See Idempotency and retries.
List orders
GET /orders returns the account's orders, newest first. Paged with limit (1 to 100, default 50) and cursor (ord_…).
curl -sS "https://api.redswitches.com/v1/orders?limit=20" \
-H "Authorization: Bearer $REDSWITCHES_API_KEY"const page = await rs.orders.list({ limit: 20 });page = client.orders.list(limit=20)page, err := client.Orders.List(ctx, &redswitches.ListOptions{Limit: 20}){
"data": [
{
"id": "ord_456",
"date": "2026-11-15T09:30:00Z",
"status": "active",
"payment": "paid",
"invoice": "inv_789",
"services": [{ "id": "srv_123", "delivery": "installing" }],
"poll_after": 30
}
],
"next_cursor": null
}
Get an order
GET /orders/{id} returns one order. Poll it after ordering until every service's delivery is ready.
curl -sS https://api.redswitches.com/v1/orders/ord_456 \
-H "Authorization: Bearer $REDSWITCHES_API_KEY"const ready = await rs.orders.waitUntilReady("ord_456");ready = client.orders.wait_until_ready("ord_456")order, err := client.Orders.Get(ctx, "ord_456"){
"id": "ord_456",
"date": "2026-11-15T09:30:00Z",
"status": "active",
"payment": "paid",
"invoice": "inv_789",
"services": [{ "id": "srv_123", "delivery": "ready" }],
"poll_after": null
}
| Field | Type | Meaning |
|---|---|---|
id | string | ord_<n>. |
date | string or null | When the order was placed (UTC). |
status | string | pending, active, cancelled, on_hold or other. |
payment | string | paid, free, unpaid, partially_paid, pending, cancelled, refunded, collections or unknown. |
invoice | string or null | The invoice id, or null while there is none. |
services | array | Each server of the order: id and delivery. |
services[].delivery | string or null | awaiting_payment, assigning, installing, ready, attention or closed. Null for a server that is not an instant server. |
poll_after | integer or null | Seconds until it is worth asking again. Null when nothing is still being delivered. |
Delivery states:
| State | Meaning |
|---|---|
awaiting_payment | The order is not paid yet. |
assigning | A server is being picked for you. |
installing | The OS is being installed. |
ready | Done. The login details are in the owner's email. |
attention | Delivery needs a look by our staff. They are on it; you do not need to order again. |
closed | The order was cancelled, refunded or is in collections, or the server was suspended or has ended. |