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 use item_id as 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 status is completed.

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 /orders with the same Idempotency-Key and body.
  • After retry — A successful replay returns the same order_id and result. You can also call GET /orders/{id} if you need to confirm the outcome.

Error handling

Common responses:

  • 400 — Purchase blocked. Check message and data.state:
    • invalid_quantityquantity is outside this SKU’s min/max.
    • out_of_stock — Not enough inventory at purchase time (wallet is not debited).
    • Terminal failure with order_id — If order_id is present, call GET /orders/{id} before treating as final; status may still be pending.
    • 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.
  • 409idempotency_conflict — Same key with a different request body, or the order is still being processed. When data.order_id is present, call GET /orders/{id} instead of refunding or creating a new order.
  • 422 — Validation error (e.g. missing item_code or invalid format).

← Check availability · Integration Guide · Order status →