API ReferenceVouchers

Create Order

Place a voucher order and receive gift card codes

POST /api/v1/orders

Create a new voucher order. Octopus Cards validates your request, checks wallet balance, deducts funds, and fulfills the order - either immediately (sync) or in the background (async).

Request

curl -X POST "https://api.octopuscards.io/api/v1/orders" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 123,
    "denomination": 50.00,
    "quantity": 5,
    "client_reference": "MY_ORDER_001",
    "email": "recipient@example.com"
  }'

Request Parameters

KeyTypeRequiredDescription
product_idintegerYesProduct ID from the catalog. Must be an active, non-blacklisted product.
denominationnumberYesFace value per voucher. Must be greater than 0 and fall within an available denomination range for the product.
quantityintegerYesNumber of vouchers to order. Minimum 1, maximum is your client's bulk limit (check max_quantity from the Charges endpoint). Absolute cap: 5,000 per request.
wallet_idintegerNoWallet to debit. If omitted, Octopus Cards uses your wallet matching the product's currency. Specify this for cross-currency orders (triggers FX conversion).
client_referencestringNoYour dedup + lookup key (printable ASCII, max 255 characters). Unique per client — a duplicate (client_id, client_reference) returns 400 "Duplicate client_reference". Optional, but required for retry-safe order creation. See Idempotency.
emailstringNoRecipient email address. Used for voucher delivery notifications. Must be a valid email format (max 254 characters).

Response (Sync - quantity ≤ 5)

When quantity is 5 or fewer, vouchers are delivered immediately:

{
  "id": 1234,
  "product_id": 123,
  "product_name": "Steam Wallet Card",
  "denomination": 50.00,
  "quantity": 5,
  "amount": 250.00,
  "discount": 8.75,
  "client_reference": "MY_ORDER_001",
  "wallet_id": 1,
  "status": "DELIVERED",
  "base_currency": "USD",
  "deduction_currency": "USD",
  "message": "Order created successfully",
  "email": "recipient@example.com",
  "vouchers": [
    {
      "card_number": "STEAM-XXXX-XXXX-XXXX",
      "pin_code": "1234",
      "claim_url": null,
      "expires_at": "2027-03-25T00:00:00Z",
      "voucher_reference_number": "VCH-001"
    },
    {
      "card_number": "STEAM-YYYY-YYYY-YYYY",
      "pin_code": "5678",
      "claim_url": null,
      "expires_at": "2027-03-25T00:00:00Z",
      "voucher_reference_number": "VCH-002"
    }
  ]
}

Response (Async - quantity > 5)

For larger orders, the response returns immediately with PENDING status and no vouchers:

{
  "id": 1235,
  "product_id": 123,
  "product_name": "Steam Wallet Card",
  "denomination": 50.00,
  "quantity": 100,
  "amount": 5000.00,
  "discount": 175.00,
  "client_reference": "BULK_ORDER_001",
  "wallet_id": 1,
  "status": "PENDING",
  "base_currency": "USD",
  "deduction_currency": "USD",
  "message": "Order created successfully",
  "email": "recipient@example.com",
  "vouchers": []
}

Poll GET /api/v1/orders/1235 to check when delivery is complete.

Response (Cross-currency order)

When paying from a different currency wallet:

{
  "id": 1236,
  "product_id": 456,
  "product_name": "Google Play Gift Card (UK)",
  "denomination": 25.00,
  "quantity": 2,
  "amount": 50.00,
  "discount": 1.50,
  "client_reference": "FX_ORDER_001",
  "wallet_id": 2,
  "status": "DELIVERED",
  "base_currency": "GBP",
  "deduction_currency": "EUR",
  "message": "Order created successfully",
  "vouchers": [
    {
      "card_number": "GPLAY-XXXX-XXXX",
      "pin_code": null,
      "claim_url": "https://play.google.com/redeem?code=XXXX",
      "expires_at": "2027-06-01T00:00:00Z",
      "voucher_reference_number": null
    }
  ]
}

base_currency is the product's currency (GBP). deduction_currency is the wallet's currency (EUR). The FX conversion details are recorded in the wallet transaction.

Response Fields

KeyTypeDescription
idintegerUnique order identifier
product_idintegerProduct that was ordered
product_namestringProduct display name
denominationnumberFace value per voucher
quantityintegerNumber of vouchers ordered
amountnumberTotal face value (denomination × quantity)
discountnumberTotal discount applied
client_referencestringEcho of the value you supplied on create (omitted if you didn't supply one)
wallet_idintegerWallet that was debited
statusstringOrder status - see Order Statuses
base_currencystringProduct's currency code
deduction_currencystringWallet's currency code (differs from base_currency in cross-currency orders)
messagestringHuman-readable status message
emailstringDelivery email (if provided)
vouchersarrayDelivered vouchers (empty if PENDING)

Voucher Fields

KeyTypeDescription
card_numberstring or nullVoucher code / gift card number
pin_codestring or nullPIN for the voucher
claim_urlstring or nullRedemption URL (for URL-based delivery)
expires_atstring or nullVoucher expiry date (RFC 3339)
voucher_reference_numberstring or nullBrand reference for the voucher

What Happens Step by Step

  1. Validate - request fields, product existence, denomination range
  2. Check duplicates - reject if client_reference was already used by this client
  3. Select wallet - use wallet_id or find the wallet matching the product's currency
  4. Calculate charges - apply discounts and FX conversion (same as the charges endpoint)
  5. Check balance - verify wallet has enough funds
  6. Debit wallet - atomically deduct the total payable amount and create a transaction record
  7. Create order - insert the order record
  8. Fulfill - for sync orders (≤ 5 qty), fetch voucher codes immediately. For async (> 5 qty), queue for background processing.
  9. Respond - return the order with vouchers (sync) or pending status (async)

Errors

400 Bad Request - Missing or invalid required fields.

{
  "error": {
    "name": "ValidationException",
    "code": "VALIDATION_FAILURE",
    "message": "Invalid product_id: required"
  }
}

On this page