How to create an order (gift cards & codes)
When a customer completes checkout, call POST /orders to create the order. For products that deliver redeemable codes (game_card, gift_card, app_store, etc.), success usually includes codes in the same response.
For direct top-up products (product_type = direct_top_up), use the dedicated guide: create a direct top-up order (requires fields and uses the delivery object).
When to use this
Call this after the customer has paid (or your system has authorized payment). You should have already checked availability for the same item and quantity. Use the item_code from the catalog.
Step 1: Send the order request
Endpoint: POST https://api.cardpluspay.com/v1/orders
Body (JSON):
item_code(required) — Product item code (e.g.GOOGLE-5USD-KOXx). You can also useitem_idas an alias.quantity(optional) — Number of units; default 1, max 100.email(optional) — Recipient email for delivery or records.
Optional header: Idempotency-Key (or X-Idempotency-Key) — A unique, stable string per purchase attempt (a UUID is recommended). Retries with the same key and body return the original result instead of creating a duplicate order.
Example request
curl -X POST "https://api.cardpluspay.com/v1/orders" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"item_code": "GOOGLE-5USD-KOXx", "quantity": 1}'
Quantity must be between the SKU’s min_quantity and max_quantity (from GET /catalog or POST /orders/check) and within platform bounds (1–100). Stock is re-validated at purchase time.
Step 2: Handle the response
Completed immediately
On success with status: completed, data includes identifiers, amounts, and gift card codes:
{
"success": true,
"message": "Gift card purchased successfully",
"data": {
"type": "bulk",
"brand": "GOOGLE-5USD-KOXx",
"codes": [
{
"code": "XXXX-XXXX-XXXX-XXXX",
"currency": "USD",
"item_code": "GOOGLE-5USD-KOXx",
"denomination": "5.00",
"charged_amount": "4.90",
"denomination_unit": "USD"
}
],
"state": "completed",
"amount": "4.90",
"status": "completed",
"order_id": 123,
"order_no": "ORD-2026-001",
"created_at": "2026-03-07T21:42:27+02:00",
"denomination_unit": "USD",
"total_denomination": 5
}
}
- order_id — Use this to check order status later.
- order_no — Human-readable order reference for your records and support.
- amount — Total amount charged for this order.
- codes — Deliver to the customer when present and
statusiscompleted.
Still processing (pending)
Some orders return HTTP 200 with status: pending and an empty or missing codes array:
{
"success": true,
"message": "Order is being processed",
"data": {
"order_id": 124,
"order_no": "ORD-2026-002",
"status": "pending",
"state": "pending",
"amount": "4.90",
"codes": []
}
}
This is not a failure. CardPlusPay is still fulfilling the order. Your API wallet has been debited. Do not create a duplicate order or refund your customer based on time alone. Poll GET /orders/{order_id} until status becomes completed (then read codes) or failed. See order status & polling.
Store order_id and order_no in your database for support and reconciliation.
Production integration
- HTTP client timeout — Configure at least 90 seconds for
POST /orders(180 seconds recommended for some SKUs). A timeout before you receive a response does not mean the order failed. - Idempotency on retry — If the connection ends before you receive a response, retry
POST /orderswith the sameIdempotency-Keyand body. - After retry — A successful replay returns the same
order_idand result. You can also callGET /orders/{id}if you need to confirm the outcome.
Error handling
Common responses:
- 400 — Purchase blocked. Check
messageanddata.state:invalid_quantity—quantityis outside this SKU’s min/max.out_of_stock— Not enough inventory at purchase time (wallet is not debited).- Terminal failure with
order_id— Iforder_idis present, callGET /orders/{id}before treating as final; status may still bepending. - Failed idempotency replay — A previous purchase with the same key already failed. Start a new purchase with a new key.
- 402 — Insufficient API wallet balance. Top up your account before retrying.
- 401 — Invalid or missing API key.
- 409 —
idempotency_conflict— Same key with a different request body, or the order is still being processed. Whendata.order_idis present, callGET /orders/{id}instead of refunding or creating a new order. - 422 — Validation error (e.g. missing
item_codeor invalid format).