How to create a direct top-up order

direct_top_up products credit a buyer account (player ID, phone, etc.) — no gift card codes are returned. This guide covers validate → purchase → poll until complete.

Prerequisites

  1. Load the SKU — confirm product_type is direct_top_up and read required_fields.
  2. Check availability — same item_code and quantity.
  3. Validate fields (recommended) — confirm buyer inputs before payment.

Step 1: Create the order

Endpoint: POST https://api.cardpluspay.com/v1/orders

Body (JSON):

  • item_code (required)
  • quantity (optional, default 1)
  • fields (required for direct_top_up) — Same object you validated; keys must match catalog required_fields[].key.
  • email (optional)

Header: Idempotency-Key — One stable UUID (or your own stable string) per purchase attempt. Retries after timeout must reuse the same key and same body including fields. Use a new key when the buyer changes account details.

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": "PUBG-60UC-TOPUP-XXXX",
    "quantity": 1,
    "fields": {
      "player_id": "5123456789"
    }
  }'

Set your HTTP client timeout to at least 90 seconds (180 seconds is safer for some SKUs). A client timeout does not mean the order failed — see order status & polling.

Step 2: Interpret the response

Completed in the same response

{
  "success": true,
  "message": "Order completed successfully",
  "data": {
    "order_id": 456,
    "order_no": "ORD-2026-042",
    "status": "completed",
    "state": "completed",
    "amount": "0.87",
    "quantity": 1,
    "codes": [],
    "delivery": {
      "mode": "direct_top_up",
      "status": "completed"
    }
  }
}
  • codes — Always empty (or omitted) for direct top-up. Success is delivery.status = completed or status = completed.
  • delivery — Present on direct top-up orders: mode is direct_top_up; status is completed, pending, or failed.

Still processing (pending)

{
  "success": true,
  "message": "Order is being processed",
  "data": {
    "order_id": 457,
    "order_no": "ORD-2026-043",
    "status": "pending",
    "state": "pending",
    "amount": "0.87",
    "quantity": 1,
    "codes": [],
    "delivery": {
      "mode": "direct_top_up",
      "status": "pending"
    }
  }
}

This is success, not failure. Your API wallet has been debited. Do not create a duplicate order. Poll GET /orders/{order_id} until status and delivery.status become completed or failed. See order status & polling.

Terminal failure

When fulfillment cannot complete, you may receive HTTP 400 with data.order_id and data.order_no for support. If you already have an order_id, call GET /orders/{id} before treating the purchase as final — the order may still be pending.

Error handling

  • 422missing_fields, invalid_fields — Fix the fields object before retrying with a new Idempotency-Key.
  • 400invalid_quantity, out_of_stock — Same as voucher orders; wallet not debited for stock failures.
  • 409idempotency_conflict — Same key with a different body, or the original order is still processing. When data.order_id is present, call GET /orders/{id} instead of starting a new purchase.
  • 501not_supported — SKU is not yet available for API purchase.
  • 402 — Insufficient API wallet balance.

Idempotency and fields

The idempotency scope includes item_code, quantity, and normalized fields. Changing the player ID (or any required field) is a new purchase — use a new Idempotency-Key.

← Validate fields · Integration Guide · Order status & polling →