Create Order
Place a voucher order and receive gift card codes
POST /api/v1/orders
Create a new voucher order. The platform validates your request, checks wallet balance, deducts funds, and fulfills the order — either immediately (sync) or in the background (async).
Request
curl -X POST "{{host}}/api/v1/orders" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"product_id": 123,
"denomination": 50.00,
"quantity": 5,
"ref": "MY_ORDER_001",
"client_reference": "CAMPAIGN_Q1_2025",
"email": "recipient@example.com"
}'package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type CreateOrderRequest struct {
ProductID int `json:"product_id"`
Denomination float64 `json:"denomination"`
Quantity int `json:"quantity"`
WalletID *int `json:"wallet_id,omitempty"`
Ref string `json:"ref,omitempty"`
ClientReference string `json:"client_reference,omitempty"`
Email string `json:"email,omitempty"`
}
type Voucher struct {
CardNumber *string `json:"card_number"`
PinCode *string `json:"pin_code"`
ClaimURL *string `json:"claim_url"`
ExpiresAt *string `json:"expires_at"`
VoucherReferenceNumber *string `json:"voucher_reference_number"`
}
type OrderResponse struct {
ID int `json:"id"`
ProductID int `json:"product_id"`
ProductName string `json:"product_name"`
Denomination float64 `json:"denomination"`
Quantity int `json:"quantity"`
Amount float64 `json:"amount"`
Discount float64 `json:"discount"`
Ref string `json:"ref"`
ClientReference string `json:"client_reference"`
WalletID int `json:"wallet_id"`
Status string `json:"status"`
BaseCurrency string `json:"base_currency"`
DeductionCurrency string `json:"deduction_currency"`
Message string `json:"message"`
Email string `json:"email"`
Vouchers []Voucher `json:"vouchers"`
}
func main() {
body, _ := json.Marshal(CreateOrderRequest{
ProductID: 123,
Denomination: 50.00,
Quantity: 5,
Ref: "MY_ORDER_001",
})
req, _ := http.NewRequest("POST", "{{host}}/api/v1/orders", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var order OrderResponse
json.NewDecoder(resp.Body).Decode(&order)
fmt.Printf("Order #%d — %s (%s)\n", order.ID, order.Status, order.Message)
for _, v := range order.Vouchers {
if v.CardNumber != nil {
fmt.Printf(" Code: %s / PIN: %s\n", *v.CardNumber, *v.PinCode)
}
if v.ClaimURL != nil {
fmt.Printf(" URL: %s\n", *v.ClaimURL)
}
}
}Request Parameters
| Key | Type | Required | Description |
|---|---|---|---|
product_id | integer | Yes | Product ID from the catalog. Must be an active, non-blacklisted product. |
denomination | number | Yes | Face value per voucher. Must be greater than 0 and fall within an available denomination range for the product. |
quantity | integer | Yes | Number 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_id | integer | No | Wallet to debit. If omitted, the platform uses your wallet matching the product's currency. Specify this for cross-currency orders (triggers FX conversion). |
ref | string | No | Your unique reference code for this order. If omitted, a UUID is generated. Must be unique — duplicate references are rejected. |
client_reference | string | No | Your internal tracking reference (max 255 characters). Does not need to be unique. |
email | string | No | Recipient email address. Used for voucher delivery notifications. Must be a valid email format. |
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,
"ref": "MY_ORDER_001",
"client_reference": "CAMPAIGN_Q1_2025",
"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,
"ref": "BULK_ORDER_001",
"client_reference": "CAMPAIGN_Q1_2025",
"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,
"ref": "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
| Key | Type | Description |
|---|---|---|
id | integer | Unique order identifier |
product_id | integer | Product that was ordered |
product_name | string | Product display name |
denomination | number | Face value per voucher |
quantity | integer | Number of vouchers ordered |
amount | number | Total face value (denomination × quantity) |
discount | number | Total discount applied |
ref | string | Order reference code (yours or auto-generated UUID) |
client_reference | string | Your internal reference (if provided) |
wallet_id | integer | Wallet that was debited |
status | string | Order status — see Order Statuses |
base_currency | string | Product's currency code |
deduction_currency | string | Wallet's currency code (differs from base_currency in cross-currency orders) |
message | string | Human-readable status message |
email | string | Delivery email (if provided) |
vouchers | array | Delivered vouchers (empty if PENDING) |
Voucher Fields
| Key | Type | Description |
|---|---|---|
card_number | string or null | Voucher code / gift card number |
pin_code | string or null | PIN for the voucher |
claim_url | string or null | Redemption URL (for URL-based delivery) |
expires_at | string or null | Voucher expiry date (RFC 3339) |
voucher_reference_number | string or null | Supplier reference for the voucher |
What Happens Step by Step
- Validate — request fields, product existence, denomination range
- Check duplicates — reject if
refwas already used - Select wallet — use
wallet_idor find the wallet matching the product's currency - Calculate charges — apply discounts and FX conversion (same as the charges endpoint)
- Check balance — verify wallet has enough funds
- Debit wallet — atomically deduct the total payable amount and create a transaction record
- Create order — insert the order record
- Fulfill — for sync orders (≤ 5 qty), fetch voucher codes immediately. For async (> 5 qty), queue for background processing.
- 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"
}
}400 Bad Request — The reference code has already been used.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Duplicate reference code"
}
}Each ref must be unique across all your orders. Use a different reference or omit it to auto-generate.
404 Not Found — Product does not exist or is not available to your client.
{
"error": {
"name": "NotFoundError",
"code": "NOT_FOUND",
"message": "Product not found"
}
}400 Bad Request — The requested denomination is not available for this product.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Denomination not available for this product"
}
}Check the product's available_denominations to see valid ranges.
400 Bad Request — Quantity exceeds your limit.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Invalid quantity, allowed max quantity: 100"
}
}Check max_quantity from the Charges endpoint to see your limit.
404 Not Found — No matching wallet found.
{
"error": {
"name": "NotFoundError",
"code": "NOT_FOUND",
"message": "Wallet not found"
}
}Either the specified wallet_id does not exist, or you have no wallet in the product's currency.
400 Bad Request — Wallet balance is too low.
{
"error": {
"name": "BadRequestError",
"code": "BAD_REQUEST",
"message": "Insufficient funds in your wallet"
}
}Use the Charges endpoint to check the exact amount required, then top up your wallet.