Place and pay for an order
Accept a quote, collect payment and handle cancellation.
Confirm an order after payment
Orders return awaiting_payment, expired, confirmed, in_production, shipped, delivered, on_hold or cancelled. Staff set the fulfillment states. shipment is filled when the order ships, and hold while it is on hold. Payment confirmation does not mean production has started. Customer cancellation ends when production starts.
Create an order from an open quote and shipping option. It starts in awaiting_payment with an expires_at deadline. Save separate idempotency keys for creation and payment, then pay the same order with a saved card or hosted Checkout.
HTTP 200 does not prove payment. Inspect payment.status, follow next_action when verification is required, then retrieve the order until its status is confirmed. Never create a replacement order while payment is unresolved.
A confirmed order has a PDF invoice. It is issued once, when payment succeeds.
An unpaid order expires at expires_at, 24 hours after creation; expires_at is null once the order leaves awaiting_payment. A payment started before then can finish until expires_at, or 1 hour after it started if that is later. After that, an unfinished payment is voided. A success found after the order expires is refunded. To change items or delivery, cancel the unpaid order and request a new quote.
Create an unpaid order
Review an open quote and choose a shipping_option_id. Use orders:write to create and orders:read to retrieve. Set QUOTE_ID, SHIPPING_OPTION_ID and a saved ORDER_REQUEST_KEY. Creating an order fixes its terms but does not charge a card.
Create an order
#!/usr/bin/env bash
# Bash + curl + jq. Requires orders:write.
set -euo pipefail
: "${API_BASE_URL:?Set API_BASE_URL}"
: "${OTTOMFG_API_KEY:?Set OTTOMFG_API_KEY}"
: "${ORDER_REQUEST_KEY:?Set ORDER_REQUEST_KEY once; save and reuse on retry}"
: "${QUOTE_ID:?Set QUOTE_ID}"
: "${SHIPPING_OPTION_ID:?Set SHIPPING_OPTION_ID}"
body=$(jq -n --arg quote_id "$QUOTE_ID" --arg shipping_option_id "$SHIPPING_OPTION_ID" '{quote_id:$quote_id, shipping_option_id:$shipping_option_id}')
result=$(curl --fail-with-body --silent --show-error --max-time 60 -X POST "${API_BASE_URL%/}/api/v1/orders" \
-H "Authorization: Bearer $OTTOMFG_API_KEY" \
-H "Idempotency-Key: $ORDER_REQUEST_KEY" \
-H "Content-Type: application/json" --data "$body") || { printf '%s\n' "$result"; exit 1; }
printf '%s\n' "$result" | jq .
A quote can have only one non-cancelled order. Another key returns 409 quote_accepted; find the existing order using List orders and quote_id. After cancellation or expiry, an unexpired quote can be accepted again with a new key. Reusing the original key still returns the original order snapshot.
Order creation revalidates revision repair coverage. repair_payment_pending means an existing order has an unpaid repair fee for that revision: pay or cancel that order first, then request a fresh quote. quote_unavailable can mean the repair request or coverage changed, or repair was paid after this quote; review a new quote instead of paying a duplicate fee.
Choose how to pay
A business administrator must enable spending on the API key; payments:write alone is not sufficient. Saving a card does not authorize an integration to spend. Listing saved cards requires payments:read; existing payments:write keys also qualify. Read access does not authorize payment. List payment methods uses limit (1–100, default 20) and cursor; follow next_cursor while has_more is true.
Hosted Checkout returns a short-lived next_action URL for your customer. Saved-card payment uses a payment_method_id from List payment methods. Only the accepted order total is charged; one attempt can be active per order.
Start hosted Checkout
#!/usr/bin/env bash
# Bash + curl + jq. Requires payments:write and explicit spending authorization.
set -euo pipefail
: "${API_BASE_URL:?Set API_BASE_URL}"
: "${OTTOMFG_API_KEY:?Set OTTOMFG_API_KEY}"
: "${ORDER_ID:?Set ORDER_ID}"
: "${PAYMENT_REQUEST_KEY:?Set PAYMENT_REQUEST_KEY once; save and reuse on retry}"
body=$(jq -n '{type:"checkout"}')
result=$(curl --fail-with-body --silent --show-error --max-time 60 -X POST "${API_BASE_URL%/}/api/v1/orders/$ORDER_ID/payments" \
-H "Authorization: Bearer $OTTOMFG_API_KEY" \
-H "Idempotency-Key: $PAYMENT_REQUEST_KEY" \
-H "Content-Type: application/json" --data "$body") || { printf '%s\n' "$result"; exit 1; }
printf '%s\n' "$result" | jq .payment
# Deliver next_action.url securely to the customer UI; poll GET order for current state.
Saved-card request body
json
{
"type": "saved_method",
"payment_method_id": "pm_example"
}Payment recovery
Save a separate PAYMENT_REQUEST_KEY before paying. HTTP 200 may contain requires_action or failed; inspect payment.status. Complete next_action when required, then retrieve the order. A return redirect alone does not prove payment. Keep payment URLs out of logs.
| Outcome | Action |
|---|---|
| requires_action for a saved card | A current member of the owning business opens next_action.url and verifies the original card. The same payment stays active; do not switch methods or create another order. |
| Timeout / 503 | Retry the same key and body with bounded backoff. |
| Failed or expired payment | Reuse the same order. A new key can start a fresh attempt or resume one that is still active. |
| payment_in_progress | Resolve the active attempt before switching methods. |
| payment_reconciliation_required | Contact support with the order ID; do not create a duplicate order. |
| paid | No further collection is needed. |
Once paid, payment.receipt_url links to the receipt when available; otherwise it is null. Retrieve the order for current payment details.
Cancellation and refunds
Cancel while status is awaiting_payment or confirmed, provided no other active order relies on its paid model repair. Cancel dependent orders first; otherwise cancellation_unavailable is returned. Successful cancellation of a paid order refunds the full amount including shipping; a payment completing during cancellation is also refunded. Poll the order while refund_pending. refund_failed requires support.
Cancel an order
#!/usr/bin/env bash
# Bash + curl + jq. Requires orders:write.
set -euo pipefail
: "${API_BASE_URL:?Set API_BASE_URL}"
: "${OTTOMFG_API_KEY:?Set OTTOMFG_API_KEY}"
: "${ORDER_ID:?Set ORDER_ID}"
# Optional key; this example saves one for safe retries within 24 hours.
: "${CANCEL_REQUEST_KEY:?Set a saved key for this request}"
body=$(jq -n '{}')
result=$(curl --fail-with-body --silent --show-error --max-time 60 -X POST "${API_BASE_URL%/}/api/v1/orders/$ORDER_ID/cancel" \
-H "Authorization: Bearer $OTTOMFG_API_KEY" \
-H "Idempotency-Key: $CANCEL_REQUEST_KEY" \
-H "Content-Type: application/json" --data "$body") || { printf '%s\n' "$result"; exit 1; }
printf '%s\n' "$result" | jq .
You can cancel an order while it is awaiting_payment or confirmed. When fulfillment states are enabled, an order in in_production, shipped, delivered or on_hold returns 409 cancellation_unavailable; contact support instead. Repeated cancellation or a repair-coverage dependency also returns 409 cancellation_unavailable. After a lost response, retrieve the existing order. Cancelled order records and their references remain available.
API v1 preview