eG
eGiftlyAPI Reference
Get API Key
v1.0.0 · Last updated July 2026

eGiftly Vendor API

Integrate digital gift card inventory, wallet balances, and order fulfillment directly into your platform. RESTful, JSON everywhere, and predictable errors.

Productionhttps://vendor.e-giftly.com/api
Sandboxhttps://sandbox.e-giftly.com/api
Quickstart · bash
# 1. Get an access token
curl -X POST https://vendor.e-giftly.com/api/login \
  -H "Content-Type: application/json" \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  -d '{"email":"vendor@example.com","password":"your_password"}'

# 2. Use the token to call any endpoint
curl https://vendor.e-giftly.com/api/wallet/balance \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"

Welcome

The eGiftly API gives resellers a complete toolkit to manage digital gift card inventory, wallets, orders, and transactions — integrate gift card fulfillment into your own platform in an afternoon.

  • User authentication and session management via JWT
  • Real-time wallet balance and transaction tracking
  • Access to a comprehensive brand and denomination catalog
  • Order creation and management, with instant voucher delivery
  • Webhook notifications for codes that resolve asynchronously
  • RESTful architecture — predictable JSON in, JSON out
Getting Started

Authentication

The Vendor API uses JWT bearer authentication. Call Login to receive an access token, then include it in the Authorization header of every subsequent request. Every request must also include the egiftly-client-id header — provided to your account by eGiftly.

Required headers

HeaderValue
AuthorizationBearer {access_token}
egiftly-client-id{your_client_id}
Token TTL: the token expires after expires_in seconds. Once expired, call Login again to obtain a fresh token — there is no refresh-token flow.

Authentication errors

Failures at the authentication layer — a missing/invalid egiftly-client-id, or an expired, invalid, or blacklisted token — return a different envelope than regular endpoint errors, shown in the panel opposite.

Auth error codes

Error IDHTTPDescription
2001422egiftly-client-id is missing from the request header
2002401Not allowed to access vendor services (unknown client ID or invalid token user)
2003401Logged in user does not match passed vendor client id
2004401Logged in user does not match passed vendor client id
2006401Token is blacklisted, please login again
2007401Token has expired, please login again
2008401Token is invalid, please login again
2009401Something went wrong while getting the token, please login again
Token response
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "bearer",
  "expires_in": 3600
}
Example request
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc..." \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  https://vendor.e-giftly.com/api/wallet/balance
401 · Auth error
{
  "error_id": 2007,
  "error_message": "token has expired, please login again"
}
Getting Started

Error Handling

The API uses standard HTTP status codes to indicate success or failure. Error responses carry a descriptive message and, where applicable, an internal error code to help you branch on the exact failure.

Status codes

StatusMeaningDescription
200OKRequest successful, response contains data
401UnauthorizedMissing or invalid authentication token
404Not FoundResource not found
422Unprocessable EntityValidation failed or business rule error — see the internal error code in the response body
429Too Many RequestsRate limit exceeded
500Server ErrorInternal server error occurred
Wallet · Authentication
POST /api/login

Login

Authenticate a vendor account and receive a JWT access token. This token must be included in the Authorization header for all subsequent requests.

Request parameters

ParameterTypeRequiredDescription
emailstringRequiredVendor account email address
passwordstringRequiredVendor account password

Error codes

CodeHTTPDescription
0200Successfully authenticated
2002422Email is missing from payload
2003422Password is missing from payload
2004422Invalid email format
2006401Invalid credentials or user not authorized
Request
curl -X POST https://vendor.e-giftly.com/api/login \
  -H "Content-Type: application/json" \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  -d '{
    "email": "vendor@example.com",
    "password": "your_password"
  }'
Request
const response = await fetch('https://vendor.e-giftly.com/api/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'egiftly-client-id': 'YOUR_CLIENT_ID'
  },
  body: JSON.stringify({
    email: 'vendor@example.com',
    password: 'your_password'
  })
});

const data = await response.json();
const token = data.data.access_token;
localStorage.setItem('token', token);
Request
$ch = curl_init('https://vendor.e-giftly.com/api/login');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'email' => 'vendor@example.com',
    'password' => 'your_password'
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'egiftly-client-id: YOUR_CLIENT_ID'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
$token = $data['data']['access_token'];
Request
$response = Http::withHeaders([
    'egiftly-client-id' => env('EGIFTLY_CLIENT_ID')
])->post('https://vendor.e-giftly.com/api/login', [
    'email' => 'vendor@example.com',
    'password' => 'your_password'
]);

$token = $response->json('data.access_token');
Response
{
  "code": 0,
  "message": "You have been logged in successfully",
  "status": "success",
  "data": {
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "token_type": "bearer",
    "expires_in": 3600
  }
}
Response
{
  "code": 2002,
  "message": "email or password are missing from your payload, please check your payload and try again",
  "status": "error",
  "data": []
}
Wallet
GET /api/wallet/balance Requires auth

Wallet Balance

Retrieve the current wallet balance and status for the authenticated vendor.

Headers

HeaderTypeRequiredDescription
AuthorizationstringRequiredBearer token from login (Bearer {token})
egiftly-client-idstringRequiredClient ID provided by eGiftly to your account

Status codes

HTTPCodeDescription
2000Balance retrieved successfully
401–Unauthorized — invalid or expired token
Request
curl -X GET https://vendor.e-giftly.com/api/wallet/balance \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch('https://vendor.e-giftly.com/api/wallet/balance', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`,
    'egiftly-client-id': clientId
  }
});

const data = await response.json();
console.log(`Balance: ${data.data.balance}`);
Request
$ch = curl_init('https://vendor.e-giftly.com/api/wallet/balance');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
$balance = $data['data']['balance'];
Request
$response = Http::withToken($token)
    ->withHeaders([
        'egiftly-client-id' => env('EGIFTLY_CLIENT_ID')
    ])
    ->get('https://vendor.e-giftly.com/api/wallet/balance');

$balance = $response->json('data.balance');
200 Response
{
  "code": 0,
  "message": "Wallet details has been returned successfully",
  "status": "success",
  "data": {
    "balance": 1500.50,
    "status": "active"
  }
}
Wallet
GET /api/wallet/transactions Requires auth

Wallet Transactions

Paginated transaction history (20 items per page). Amounts are always positive — the transactionType field (fund or deduct) indicates the direction.

Query parameters

ParameterTypeRequiredDescription
pageintegerOptionalPage number (default: 1)
typestringOptionalFilter by transaction type: fund or deduct
transactionIdstringOptionalFilter by transaction ID
transactionNumberintegerOptionalFilter by transaction number

Status codes

HTTPCodeDescription
2000Transactions retrieved successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/wallet/transactions?page=1&type=deduct" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch(
  'https://vendor.e-giftly.com/api/wallet/transactions',
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
200 Response
{
  "code": 0,
  "message": "Wallet transactions list has been returned successfully",
  "status": "success",
  "data": {
    "data": [
      {
        "transactionNumber": 1001,
        "transactionId": "0e8f2b9c-6a3d-4f1e-9c2a-7b5d8e4f1a23",
        "transactionType": "deduct",
        "TransactionAmount": "100.00",
        "balanceBeforeTransaction": "1600.50",
        "balanceAfterTransaction": "1500.50",
        "transactionDate": "2026-03-18 14:20:00"
      },
      {
        "transactionNumber": 1000,
        "transactionId": "3f7a1c2d-8b4e-4a6f-b1c9-2e5d7f8a9b34",
        "transactionType": "fund",
        "TransactionAmount": "50.00",
        "balanceBeforeTransaction": "1450.50",
        "balanceAfterTransaction": "1500.50",
        "transactionDate": "2026-03-17 10:15:00"
      }
    ],
    "current_page": 1,
    "last_page": 5,
    "per_page": 20,
    "total": 100
  }
}
Catalog
GET /api/brands Requires auth

Brands List

Get a paginated list of all available brands, including ID, name, and category.

Query parameters

ParameterTypeRequiredDescription
per_pageintegerOptionalItems per page (default: 20)
pageintegerOptionalPage number for pagination (default: 1)
brandNamestringOptionalFilter by brand name (partial match / wildcard search)
brandIdintegerOptionalFilter by brand ID

Status codes

HTTPCodeDescription
2000Brands retrieved successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/brands?per_page=20&page=1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch('https://vendor.e-giftly.com/api/brands?per_page=20', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`,
    'egiftly-client-id': clientId
  }
});

const data = await response.json();
data.data.data.forEach(brand => {
  console.log(`${brand.brand_name} - ${brand.category_name}`);
});
Request
$ch = curl_init('https://vendor.e-giftly.com/api/brands');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);

foreach ($data['data']['data'] as $brand) {
    echo $brand['brand_name'] . "\n";
}
Request
$response = Http::withToken($token)
    ->withHeaders([
        'egiftly-client-id' => env('EGIFTLY_CLIENT_ID')
    ])
    ->get('https://vendor.e-giftly.com/api/brands', [
        'per_page' => 20,
        'page' => 1
    ]);

$brands = $response->json('data.data');
200 Response
{
  "code": 0,
  "message": "",
  "status": "success",
  "data": {
    "data": [
      { "brand_id": 1, "brand_name": "Amazon", "category_name": "Retail" },
      { "brand_id": 2, "brand_name": "iTunes", "category_name": "Digital" },
      { "brand_id": 3, "brand_name": "Playstation", "category_name": "Gaming" }
    ],
    "current_page": 1,
    "last_page": 8,
    "per_page": 20,
    "total": 150,
    "next_page_url": "https://vendor.e-giftly.com/api/brands?page=2",
    "prev_page_url": null
  }
}
Catalog
GET /api/denominations/list Requires auth

Denominations List

Get a paginated list of available denominations — values, pricing, and branding information.

Query parameters

ParameterTypeRequiredDescription
brandIdintegerOptionalFilter by brand ID
denominationIdintegerOptionalFilter by specific denomination ID
denominationNamestringOptionalFilter by denomination name (wildcard search)
per_pageintegerOptionalItems per page (default: 20)
pageintegerOptionalPage number for pagination (default: 1)
demominationUniqueRecordId and suggestedPrice are only present when the denomination has an active supplier integration record. Denominations without one return the base fields only.

Status codes

HTTPCodeDescription
2000Denominations retrieved successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/denominations/list?brandId=1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch(
  'https://vendor.e-giftly.com/api/denominations/list?brandId=1',
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
data.data.data.forEach(d => {
  console.log(`${d.denominationName} - $${d.price}`);
});
Request
$ch = curl_init('https://vendor.e-giftly.com/api/denominations/list?brandId=1');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);

foreach ($data['data']['data'] as $denom) {
    echo $denom['denominationName'] . "\n";
}
Request
$response = Http::withToken($token)
    ->withHeaders([
        'egiftly-client-id' => env('EGIFTLY_CLIENT_ID')
    ])
    ->get('https://vendor.e-giftly.com/api/denominations/list', [
        'brandId' => 1,
        'per_page' => 20
    ]);

$denominations = $response->json('data.data');
200 Response
{
  "code": 0,
  "message": "Denominations list has been returned successfully",
  "status": "success",
  "data": {
    "data": [
      {
        "brandId": 1,
        "brandName": "Amazon",
        "denominationId": 101,
        "denominationName": "$10",
        "price": 9.75,
        "currency": "USD",
        "egiftlyLogo": "https://cdn.e-giftly.com/logos/amazon-10.png",
        "demominationUniqueRecordId": 501,
        "suggestedPrice": 10.238
      },
      {
        "brandId": 1,
        "brandName": "Amazon",
        "denominationId": 102,
        "denominationName": "$25",
        "price": 24.38,
        "currency": "USD",
        "egiftlyLogo": "https://cdn.e-giftly.com/logos/amazon-25.png",
        "demominationUniqueRecordId": 502,
        "suggestedPrice": 25.594
      }
    ],
    "current_page": 1,
    "last_page": 10,
    "per_page": 20,
    "total": 200
  }
}
Catalog
GET /api/denominations/{denominationId} Requires auth

Denomination Details

Get detailed information about a specific denomination, including pricing, suggested price, unique record ID, and live stock availability (available, inStock, canBePending).

Path parameters

ParameterTypeRequiredDescription
denominationIdintegerRequiredDenomination ID

Status codes

HTTPCodeDescription
2000Denomination details retrieved
4040Denomination not found — note the body still carries code 0 / status success; rely on the HTTP status
Request
curl -X GET "https://vendor.e-giftly.com/api/denominations/101" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const denomId = 101;
const response = await fetch(
  `https://vendor.e-giftly.com/api/denominations/${denomId}`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
console.log(`Price: $${data.data.price}`);
Response
{
  "code": 0,
  "message": "Denomination details has been returned successfully",
  "status": "success",
  "data": {
    "brandId": 1,
    "denominationId": 101,
    "denominationName": "$10",
    "price": 9.75,
    "egiftlyLogo": "https://cdn.e-giftly.com/logos/amazon-10.png",
    "available": true,
    "currency": "USD",
    "uniqueDenominationId": 501,
    "suggestedPrice": 10.238,
    "inStock": true,
    "canBePending": false
  }
}
Response
{
  "code": 0,
  "message": "This denomination is not exist in our database, please check the denomination ID and try again",
  "status": "success",
  "data": []
}
Orders
GET /api/order/list Requires auth

Orders List

Get a paginated list of all orders placed by the vendor, with status, amounts, and codes. orderStatus is one of success, canceled, pending, or refunded; orderType is Card Order or Direct Topup.

Query parameters

ParameterTypeRequiredDescription
pageintegerOptionalPage number (default: 1)
per_pageintegerOptionalItems per page (default: 20)

Status codes

HTTPCodeDescription
2000Orders retrieved successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/order/list?page=1&per_page=20" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch(
  'https://vendor.e-giftly.com/api/order/list',
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
console.log(`Total Orders: ${data.data.total}`);
200 Response
{
  "code": 0,
  "message": "Orders list has been returned successfully ",
  "status": "success",
  "data": {
    "data": [
      {
        "orderId": 5432,
        "orderStatus": "success",
        "orderCreationDate": "2026-03-18 14:20:00",
        "orderTransactionId": "0e8f2b9c-6a3d-4f1e-9c2a-7b5d8e4f1a23",
        "orderAmount": "100.00",
        "orderType": "Card Order",
        "vendorOrderUniqueId": "CUST-ORD-001",
        "codes": [
          {
            "brandName": "Amazon",
            "brandId": 1,
            "denominationName": "$50",
            "code": "XXXX-XXXX-XXXX-XXXX",
            "serialNumber": "SN123456789",
            "expiryDate": "2027-03-18",
            "created_at": "2026-03-18"
          }
        ]
      },
      {
        "orderId": 5431,
        "orderStatus": "success",
        "orderCreationDate": "2026-03-17 10:15:00",
        "orderTransactionId": "3f7a1c2d-8b4e-4a6f-b1c9-2e5d7f8a9b34",
        "orderAmount": "50.00",
        "orderType": "Card Order",
        "vendorOrderUniqueId": "CUST-ORD-002",
        "codes": [
          {
            "brandName": "iTunes",
            "brandId": 2,
            "denominationName": "$25",
            "code": "YYYY-YYYY-YYYY-YYYY",
            "serialNumber": "SN987654321",
            "expiryDate": "2027-03-17",
            "created_at": "2026-03-17"
          }
        ]
      }
    ],
    "current_page": 1,
    "last_page": 5,
    "per_page": 20,
    "total": 100
  }
}
Orders
POST /api/order/create Requires auth

Create Order

Create a new order for gift cards. Deducts funds from the vendor wallet and returns voucher codes immediately on success.

Body parameters

ParameterTypeRequiredDescription
uniqueOrderIdstringRequiredUnique order identifier from vendor system (max 255 characters)
denominationIdintegerRequiredDenomination ID to order (minimum: 1)
quantityintegerOptionalNumber of cards to order (1–500, default: 1)

Error codes

HTTPCodeDescription
2000Order created successfully
4223001uniqueOrderId is missing or invalid
4223003denominationId or quantity is missing or invalid
4043005Denomination does not exist in database
4223006Picked denomination is inactive or not found
4223007Insufficient wallet balance
4223008Issue while deducting from wallet
4223009Error while creating order
4043010Vendor wallet not found
Partial orders: if fewer codes are available than requested, the response shows purchasedQuantity less than requestedQuantity, and the difference is refunded to your wallet.
Request
curl -X POST https://vendor.e-giftly.com/api/order/create \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "uniqueOrderId": "CUST-ORD-001",
    "denominationId": 101,
    "quantity": 2
  }'
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch('https://vendor.e-giftly.com/api/order/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'egiftly-client-id': clientId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    uniqueOrderId: 'CUST-ORD-001',
    denominationId: 101,
    quantity: 2
  })
});

const data = await response.json();
if (data.status === 'success') {
  console.log(`Order ID: ${data.data.orderId}`);
  console.log(`Codes:`, data.data.code);
}
Request
$ch = curl_init('https://vendor.e-giftly.com/api/order/create');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'uniqueOrderId' => 'CUST-ORD-001',
    'denominationId' => 101,
    'quantity' => 2
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId,
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
if ($data['status'] === 'success') {
    $orderId = $data['data']['orderId'];
}
Request
$response = Http::withToken($token)
    ->withHeaders([
        'egiftly-client-id' => env('EGIFTLY_CLIENT_ID')
    ])
    ->post('https://vendor.e-giftly.com/api/order/create', [
        'uniqueOrderId' => 'CUST-ORD-001',
        'denominationId' => 101,
        'quantity' => 2
    ]);

if ($response->json('status') === 'success') {
    $orderId = $response->json('data.orderId');
    $codes = $response->json('data.code');
}
Response
{
  "code": 0,
  "message": "Order has been created successfully",
  "status": "success",
  "data": {
    "orderId": 5432,
    "transactionId": "0e8f2b9c-6a3d-4f1e-9c2a-7b5d8e4f1a23",
    "orderAmount": 100.00,
    "deductedAmount": 100.00,
    "balanceAfterPurchase": 1400.50,
    "requestedQuantity": 2,
    "purchasedQuantity": 2,
    "code": [
      {
        "brandName": "Amazon",
        "denominationName": "$50",
        "code": "XXXX-XXXX-XXXX-XXXX",
        "serialNumber": "SN123456789",
        "expiryDate": "2027-03-18",
        "created_at": "2026-03-18T14:20:00.000000Z"
      },
      {
        "brandName": "Amazon",
        "denominationName": "$50",
        "code": "YYYY-YYYY-YYYY-YYYY",
        "serialNumber": "SN987654321",
        "expiryDate": "2027-03-18",
        "created_at": "2026-03-18T14:20:00.000000Z"
      }
    ]
  }
}
Response
{
  "code": 3007,
  "message": "Your wallet does not have enough balance to make this purchase",
  "status": "error",
  "data": []
}
Orders
GET /api/order/codes/{orderId} Requires auth

Order Codes

Retrieve voucher codes and delivery information for a completed order — all codes with expiry dates and serial numbers.

Path parameters

ParameterTypeRequiredDescription
orderIdintegerRequiredOrder ID to retrieve codes for

Status codes

HTTPCodeDescription
2000Order codes retrieved
500–Order ID does not exist or does not belong to your account
Request
curl -X GET "https://vendor.e-giftly.com/api/order/codes/5432" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const orderId = 5432;
const response = await fetch(
  `https://vendor.e-giftly.com/api/order/codes/${orderId}`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
data.data.codes.forEach(code => {
  console.log(`Code: ${code.code}`);
});
200 Response
{
  "code": 0,
  "message": "Order has been returned successfully ",
  "status": "success",
  "data": {
    "orderId": 5432,
    "orderStatus": "success",
    "orderCreationDate": "2026-03-18 14:20:00",
    "orderTransactionId": "0e8f2b9c-6a3d-4f1e-9c2a-7b5d8e4f1a23",
    "orderAmount": "100.00",
    "orderType": "Card Order",
    "vendorOrderUniqueId": "CUST-ORD-001",
    "codes": [
      {
        "brandName": "Amazon",
        "brandId": 1,
        "denominationId": 101,
        "denominationName": "$50",
        "denominationPaidPricePerItem": "48.75",
        "code": "XXXX-XXXX-XXXX-XXXX",
        "serialNumber": "SN123456789",
        "expiryDate": "2027-03-18",
        "created_at": "2026-03-18"
      },
      {
        "brandName": "Amazon",
        "brandId": 1,
        "denominationId": 101,
        "denominationName": "$50",
        "denominationPaidPricePerItem": "48.75",
        "code": "YYYY-YYYY-YYYY-YYYY",
        "serialNumber": "SN987654321",
        "expiryDate": "2027-03-18",
        "created_at": "2026-03-18"
      }
    ]
  }
}
Direct Topup
GET /api/topups/denominations Requires auth

Topup Denominations

List the eGiftly direct top-up catalog available to your account — recharge products such as game credits (e.g. PUBG UC-style products) that are fulfilled directly against a player/customer account instead of issuing a redeemable code. Pricing already includes your account's markup; no supplier information is ever included in this response.

Query parameters

ParameterTypeRequiredDescription
brandIdintegerOptionalFilter by brand ID
per_pageintegerOptionalItems per page (default: 20)
pageintegerOptionalPage number for pagination (default: 1)
available reflects whether an active supplier mapping currently exists for the item — an unavailable denomination is still listed, but Create Topup against it will fail.

Status codes

HTTPCodeDescription
2000Top-up denominations retrieved successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/topups/denominations?brandId=12" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch(
  'https://vendor.e-giftly.com/api/topups/denominations?brandId=12',
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
data.data.items.forEach(item => {
  console.log(`${item.brand.name} - ${item.name} - $${item.price}`);
});
200 Response
{
  "code": 0,
  "message": "Top-up denominations fetched successfully",
  "status": "success",
  "data": {
    "items": [
      {
        "id": 301,
        "brand": { "id": 12, "name": "PUBG Mobile" },
        "name": "660 UC",
        "price": 9.99,
        "currency": "USD",
        "available": true
      },
      {
        "id": 302,
        "brand": { "id": 12, "name": "PUBG Mobile" },
        "name": "1800 UC",
        "price": 24.5,
        "currency": "USD",
        "available": true
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 20,
      "total": 45,
      "total_pages": 3
    }
  }
}
Direct Topup
GET /api/topups/denominations/{id}/config Requires auth

Topup Config

Get the dynamic customer-input schema for a top-up denomination, so you can render the right form fields (player ID, server, zone, etc.) without hard-coding anything per product. The schema reflects the highest-priority active supplier mapping for this denomination — the same one that will actually fulfill a purchase made right now via Create Topup.

Path parameters

ParameterTypeRequiredDescription
idintegerRequiredTop-up denomination ID (from Topup Denominations)

Response field schema

FieldTypeDescription
keystringParameter key to send back in parameters when creating the top-up
labelstringHuman-readable label for the field
typestringInput type, e.g. string or select
requiredbooleanAlways true — every returned field must be supplied
optionsarray|nullChoice list when type is select; null otherwise

Status codes

HTTPCodeDescription
2000Configuration retrieved successfully
4046002This top-up denomination does not exist or is not available
4226006This top-up denomination is not currently fulfillable, please try again later
Request
curl -X GET "https://vendor.e-giftly.com/api/topups/denominations/301/config" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const denomId = 301;
const response = await fetch(
  `https://vendor.e-giftly.com/api/topups/denominations/${denomId}/config`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
data.data.fields.forEach(f => console.log(f.key, f.label, f.type));
Response
{
  "code": 0,
  "message": "Top-up denomination configuration fetched successfully",
  "status": "success",
  "data": {
    "denominationId": 301,
    "fields": [
      { "key": "playerId", "label": "Player ID", "type": "string", "required": true, "options": null },
      { "key": "serverId", "label": "Server", "type": "select", "required": true, "options": ["Asia", "Europe", "NA"] }
    ]
  }
}
Response
{
  "code": 6002,
  "message": "This top-up denomination does not exist or is not available",
  "status": "error",
  "data": []
}
Response
{
  "code": 6006,
  "message": "This top-up denomination is not currently fulfillable, please try again later",
  "status": "error",
  "data": []
}
Direct Topup
POST /api/topups Requires auth

Create Topup

Submit a direct top-up for a customer's account or player ID. Deducts the priced amount from your wallet and forwards the purchase to the fulfilling supplier. Unlike Create Order, a top-up does not return a redeemable code — it resolves asynchronously against the customer's account, so the response reflects the order's state right after submission, not its final outcome. Poll Topup Status or listen for Topup Webhooks to know when it completes.

Headers

HeaderTypeRequiredDescription
Idempotency-KeystringOptionalExtra idempotency guard on top of customer_reference — replaying the same key returns the original order instead of creating or charging a new one

Body parameters

ParameterTypeRequiredDescription
denomination_idintegerRequiredTop-up denomination ID to purchase (minimum: 1)
customer_referencestringRequiredYour unique reference for this top-up (max 255 characters). Reusing the same reference for the same vendor replays the original order rather than charging again
parametersobjectRequiredKey/value pairs matching the keys returned by Topup Config for this denomination (e.g. player ID, server)
Order status: status is one of pending, processing, completed, failed, refunded, or unknown. unknown means the supplier request itself failed or timed out — the purchase may or may not have gone through on their end, so it is held for manual reconciliation rather than assumed successful or failed.

Error codes

HTTPCodeDescription
2000Top-up request submitted (or idempotent replay of an already-processed request)
4226001Invalid request payload — see the message for the specific field
4046002This top-up denomination does not exist
4226003This top-up denomination is currently unavailable
4226004One or more parameters values failed validation against the field schema
4046005Vendor wallet not found
4226005Insufficient wallet balance
4226006No active supplier mapping currently available for this denomination
4226007Unable to charge your wallet for this purchase
4226011The provided account/player information could not be verified
Request
curl -X POST https://vendor.e-giftly.com/api/topups \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1a3e2b-9c4d-4a5e-8b7c-1d2e3f4a5b6c" \
  -d '{
    "denomination_id": 301,
    "customer_reference": "CUST-TOPUP-001",
    "parameters": {
      "playerId": "5123456789",
      "serverId": "Asia"
    }
  }'
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch('https://vendor.e-giftly.com/api/topups', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'egiftly-client-id': clientId,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID()
  },
  body: JSON.stringify({
    denomination_id: 301,
    customer_reference: 'CUST-TOPUP-001',
    parameters: {
      playerId: '5123456789',
      serverId: 'Asia'
    }
  })
});

const data = await response.json();
if (data.status === 'success') {
  console.log(`Topup ID: ${data.data.id}, status: ${data.data.status}`);
}
Request
$ch = curl_init('https://vendor.e-giftly.com/api/topups');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'denomination_id' => 301,
    'customer_reference' => 'CUST-TOPUP-001',
    'parameters' => [
        'playerId' => '5123456789',
        'serverId' => 'Asia'
    ]
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId,
    'Content-Type: application/json',
    'Idempotency-Key: ' . \Illuminate\Support\Str::uuid()
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
if ($data['status'] === 'success') {
    $topupId = $data['data']['id'];
}
Request
$response = Http::withToken($token)
    ->withHeaders([
        'egiftly-client-id' => env('EGIFTLY_CLIENT_ID'),
        'Idempotency-Key' => (string) Str::uuid()
    ])
    ->post('https://vendor.e-giftly.com/api/topups', [
        'denomination_id' => 301,
        'customer_reference' => 'CUST-TOPUP-001',
        'parameters' => [
            'playerId' => '5123456789',
            'serverId' => 'Asia'
        ]
    ]);

if ($response->json('status') === 'success') {
    $topupId = $response->json('data.id');
    $status = $response->json('data.status');
}
Response
{
  "code": 0,
  "message": "Top-up request has been submitted",
  "status": "success",
  "data": {
    "id": 9001,
    "customerReference": "CUST-TOPUP-001",
    "denominationId": 301,
    "status": "processing",
    "price": 10.49,
    "currency": "USD",
    "createdAt": "2026-08-20T14:20:00.000000Z",
    "completedAt": null
  }
}
Response
{
  "code": 6005,
  "message": "Your wallet does not have enough balance to make this purchase",
  "status": "error",
  "data": []
}
Direct Topup
GET /api/topups/{id}/status Requires auth

Topup Status

Poll the current status of a top-up order — useful while it is still pending, processing, or unknown. Prefer Topup Webhooks for real-time updates and use this endpoint to reconcile or for a manual check.

Path parameters

ParameterTypeRequiredDescription
idintegerRequiredTop-up order ID, as returned in id from Create Topup or Topup Webhooks

Status codes

HTTPCodeDescription
2000Top-up order status retrieved
4046010This top-up order does not exist, or does not belong to your account
Request
curl -X GET "https://vendor.e-giftly.com/api/topups/9001/status" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const topupId = 9001;
const response = await fetch(
  `https://vendor.e-giftly.com/api/topups/${topupId}/status`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
console.log(`Status: ${data.data.status}`);
Response
{
  "code": 0,
  "message": "Top-up order status fetched successfully",
  "status": "success",
  "data": {
    "id": 9001,
    "customerReference": "CUST-TOPUP-001",
    "denominationId": 301,
    "status": "completed",
    "price": 10.49,
    "currency": "USD",
    "createdAt": "2026-08-20T14:20:00.000000Z",
    "completedAt": "2026-08-20T14:20:42.000000Z"
  }
}
Response
{
  "code": 6010,
  "message": "This top-up order does not exist",
  "status": "error",
  "data": []
}
Range Orders
GET /api/range-denominations/list Requires auth

Range Denominations

List the eGiftly range / open-amount catalog available to your account — products such as Binance USDT vouchers or open-value gift cards where the customer chooses a custom face value within a min/max range, instead of picking a fixed SKU. Pricing already includes your account's markup; no supplier information is ever included in this response. If the same product is offered by more than one supplier, only the highest-priority active mapping is shown — you never see duplicate entries for one product.

Query parameters

ParameterTypeRequiredDescription
brandIdintegerOptionalFilter by brand ID
code is an opaque identifier (e.g. RD-1MUZNII9) — never the internal denomination id, and never a sequential number you can enumerate. Save it as-is; it stays valid even if the product's backing supplier changes later. Use it as-is in Create Range Order.

Status codes

HTTPCodeDescription
2000Range denominations fetched successfully
401–Unauthorized — invalid token
Request
curl -X GET "https://vendor.e-giftly.com/api/range-denominations/list?brandId=103" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch(
  'https://vendor.e-giftly.com/api/range-denominations/list?brandId=103',
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
data.data.forEach(item => {
  console.log(`${item.name} - ${item.minAmount}-${item.maxAmount} ${item.currency} @ ${item.unitPrice}/unit`);
});
200 Response
{
  "code": 0,
  "message": "Range denominations fetched successfully",
  "status": "success",
  "data": [
    {
      "code": "RD-1MUZNII9",
      "name": "Binance 1 - 500 USDT Open Amount",
      "brandId": 103,
      "brandName": "Binance",
      "currency": "USD",
      "minAmount": 1.1,
      "maxAmount": 500,
      "unitPrice": 1.04
    }
  ]
}
Range Orders
GET /api/range-denominations/{code} Requires auth

Range Denomination Details

Fetch a single range denomination by its opaque code — the same shape as one item from Range Denominations. Useful to re-check current pricing and min/max before submitting Create Range Order, since both are resolved fresh against the current priority supplier mapping every time.

Path parameters

ParameterTypeRequiredDescription
codestringRequiredRange denomination code, as returned in code from Range Denominations

Status codes

HTTPCodeDescription
2000Range denomination fetched successfully
4046002This range denomination does not exist
Request
curl -X GET "https://vendor.e-giftly.com/api/range-denominations/RD-1MUZNII9" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const code = 'RD-1MUZNII9';
const response = await fetch(
  `https://vendor.e-giftly.com/api/range-denominations/${code}`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
console.log(`${data.data.minAmount}-${data.data.maxAmount} ${data.data.currency}`);
Response
{
  "code": 0,
  "message": "Range denomination fetched successfully",
  "status": "success",
  "data": {
    "code": "RD-1MUZNII9",
    "name": "Binance 1 - 500 USDT Open Amount",
    "brandId": 103,
    "brandName": "Binance",
    "currency": "USD",
    "minAmount": 1.1,
    "maxAmount": 500,
    "unitPrice": 1.04
  }
}
Response
{
  "code": 6002,
  "message": "This range denomination does not exist",
  "status": "error",
  "data": []
}
Range Orders
POST /api/range-orders/create Requires auth

Create Range Order

Submit a range/open-amount order for a customer-chosen face value. Deducts the priced amount from your wallet and forwards the purchase to the fulfilling supplier. Unlike a top-up, a range order does produce a real, redeemable code — but like a top-up, fulfillment happens asynchronously (a live supplier call can take a few seconds), so the response reflects the order's state right after submission, not its final outcome. Poll Range Order Status or listen for Range Webhooks to get the code once it's ready.

Body parameters

ParameterTypeRequiredDescription
uniqueOrderIdstringRequiredYour own idempotency key (max 255 characters). Retrying the same value returns the original order instead of charging again
codestringRequiredRange denomination code, from Range Denominations
amountnumberRequiredRequested face value, in the denomination's own currency. Must fall within minAmount/maxAmount for the product (minimum: 0.01)
Order status: status is one of processing, completed, failed, or refunded. orderId is an opaque identifier (e.g. RG-20260909162409HU56) — save it as-is to poll Range Order Status.

Error codes

HTTPCodeDescription
2000Range order submitted (or idempotent replay of an already-processed request)
4226001Invalid request payload — see the message for the specific field
4046002This range denomination does not exist
4226004amount is outside the product's min/max range — see the message for the exact bound
4046005Vendor wallet not found
4226005Insufficient wallet balance
4226007Unable to charge your wallet for this purchase
4226008There was an issue creating your order — the charge, if any, was automatically refunded
Request
curl -X POST https://vendor.e-giftly.com/api/range-orders/create \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "uniqueOrderId": "CUST-RANGE-001",
    "code": "RD-1MUZNII9",
    "amount": 10
  }'
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const response = await fetch('https://vendor.e-giftly.com/api/range-orders/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'egiftly-client-id': clientId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    uniqueOrderId: 'CUST-RANGE-001',
    code: 'RD-1MUZNII9',
    amount: 10
  })
});

const data = await response.json();
if (data.status === 'success') {
  console.log(`Order ID: ${data.data.orderId}, status: ${data.data.status}`);
}
Request
$ch = curl_init('https://vendor.e-giftly.com/api/range-orders/create');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'uniqueOrderId' => 'CUST-RANGE-001',
    'code' => 'RD-1MUZNII9',
    'amount' => 10
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $token,
    'egiftly-client-id: ' . $clientId,
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$data = json_decode($response, true);
if ($data['status'] === 'success') {
    $orderId = $data['data']['orderId'];
}
Request
$response = Http::withToken($token)
    ->withHeaders(['egiftly-client-id' => env('EGIFTLY_CLIENT_ID')])
    ->post('https://vendor.e-giftly.com/api/range-orders/create', [
        'uniqueOrderId' => 'CUST-RANGE-001',
        'code' => 'RD-1MUZNII9',
        'amount' => 10
    ]);

if ($response->json('status') === 'success') {
    $orderId = $response->json('data.orderId');
    $status = $response->json('data.status');
}
Response
{
  "code": 0,
  "message": "Range order has been submitted",
  "status": "success",
  "data": {
    "orderId": "RG-20260909162409HU56",
    "uniqueOrderId": "CUST-RANGE-001",
    "status": "processing",
    "requestedAmount": 10,
    "price": 10.40,
    "currency": "USD",
    "createdAt": "2026-09-09T16:24:09.000000Z",
    "code": null
  }
}
Response
{
  "code": 6004,
  "message": "Amount must be at most 500.0000",
  "status": "error",
  "data": []
}
Range Orders
GET /api/range-orders/{orderNumber}/status Requires auth

Range Order Status

Poll the current status of a range order — useful while it is still processing. Prefer Range Webhooks for real-time delivery of the code and use this endpoint to reconcile or for a manual check.

Path parameters

ParameterTypeRequiredDescription
orderNumberstringRequiredOpaque order ID, as returned in orderId from Create Range Order or Range Webhooks

Status codes

HTTPCodeDescription
2000Order status fetched successfully
4046010This order does not exist, or does not belong to your account
Request
curl -X GET "https://vendor.e-giftly.com/api/range-orders/RG-20260909162409HU56/status" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "egiftly-client-id: YOUR_CLIENT_ID"
Request
const token = localStorage.getItem('token');
const clientId = 'YOUR_CLIENT_ID';
const orderId = 'RG-20260909162409HU56';
const response = await fetch(
  `https://vendor.e-giftly.com/api/range-orders/${orderId}/status`,
  {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${token}`,
      'egiftly-client-id': clientId
    }
  }
);

const data = await response.json();
console.log(`Status: ${data.data.status}`);
Response
{
  "code": 0,
  "message": "Order status fetched successfully",
  "status": "success",
  "data": {
    "orderId": "RG-20260909162409HU56",
    "uniqueOrderId": "CUST-RANGE-001",
    "status": "completed",
    "requestedAmount": 10,
    "price": 10.40,
    "currency": "USD",
    "createdAt": "2026-09-09T16:24:09.000000Z",
    "code": {
      "code": "BMD49AHC7WX8EV66",
      "serialNumber": "",
      "expiryDate": null
    }
  }
}
Response
{
  "code": 0,
  "message": "Order status fetched successfully",
  "status": "success",
  "data": {
    "orderId": "RG-20260909162409HU56",
    "uniqueOrderId": "CUST-RANGE-001",
    "status": "processing",
    "requestedAmount": 10,
    "price": 10.40,
    "currency": "USD",
    "createdAt": "2026-09-09T16:24:09.000000Z",
    "code": null
  }
}
Response
{
  "code": 6010,
  "message": "This order does not exist",
  "status": "error",
  "data": []
}
Webhooks
POST Sent to your configured webhook URL

Code Webhooks

Some suppliers don't deliver a code instantly — the order goes pending and the code is fetched later by a background process. When that happens, eGiftly notifies you by sending a webhook to the webhook URL configured on your account (contact your account manager to set or change it). One webhook is sent per code as each pending code resolves. If your account has no webhook URL configured, no webhooks are sent — keep polling GET /api/order/codes/{orderId} instead.

Delivery

MethodPOST with a JSON body
Headersclient-id: {your_vendor_client_id}, Content-Type: application/json
Expected responseRespond with HTTP 200 to acknowledge receipt
RetriesNon-200 (or failed) deliveries are retried every 5 minutes, up to 5 attempts, with the identical payload
IdempotencyDeduplicate on eventReference — retries reuse the same value

Common fields

FieldTypeDescription
eventstringorder.code.ready or order.code.refunded
eventReferenceintegerUnique reference for this event — use it to deduplicate retries
orderIdintegereGiftly order ID (same as Orders List / Order Codes)
vendorOrderUniqueIdstringThe uniqueOrderId you sent when creating the order
pendingCodesRemainingintegerCodes of this order still pending after this event — 0 means fully resolved
datestringEvent timestamp (ISO 8601)
signaturestringSignature of the payload — see verification below

How the signature is generated

eGiftly builds the signature from the payload itself using the vendor_public_key and vendor_secret_key provided to your account:

  1. Take the payload without the signature field, keys in the exact order shown in the payload examples.
  2. Serialize to JSON using PHP json_encode() defaults — no spaces, forward slashes escaped as \/.
  3. Encrypt with AES-256-CBC — vendor_public_key as the encryption key, vendor_secret_key as the IV (first 16 bytes if longer).
  4. Base64-encode the output a second time. The result is the signature value.
Not using PHP? JSON serialization differs across languages (e.g. JS's JSON.stringify() doesn't escape slashes). Prefer the decrypt approach: decrypt the signature with AES-256-CBC, parse the resulting JSON, and compare field values against the received payload instead of comparing raw strings.
Payload
{
  "event": "order.code.ready",
  "eventReference": 9812,
  "orderId": 5432,
  "vendorOrderUniqueId": "CUST-ORD-001",
  "code": {
    "brandName": "Amazon",
    "brandId": 1,
    "denominationId": 101,
    "denominationName": "$50",
    "code": "XXXX-XXXX-XXXX-XXXX",
    "serialNumber": "SN123456789",
    "expiryDate": null,
    "created_at": "2026-07-23T14:20:00.000000Z"
  },
  "pendingCodesRemaining": 0,
  "date": "2026-07-23T14:20:00.000000Z",
  "signature": "b64EncodedSignatureString=="
}
Payload
{
  "event": "order.code.refunded",
  "eventReference": 9813,
  "orderId": 5432,
  "vendorOrderUniqueId": "CUST-ORD-001",
  "refund": {
    "brandName": "Amazon",
    "brandId": 1,
    "denominationId": 101,
    "denominationName": "$50",
    "refundedAmount": 48.75,
    "orderFullyRefunded": false
  },
  "pendingCodesRemaining": 0,
  "date": "2026-07-23T14:20:00.000000Z",
  "signature": "b64EncodedSignatureString=="
}
PHP · generate signature
// $payload = webhook body WITHOUT "signature", keys in received order
$signature = base64_encode(
    openssl_encrypt(
        json_encode($payload),
        'AES-256-CBC',
        $yourPublicKey,   // provided by eGiftly (encryption key)
        0,                // options = 0, openssl returns base64 output
        $yourSecretKey    // provided by eGiftly (used as the IV)
    )
);
PHP · verify
$payload = json_decode($request->getContent(), true);

$receivedSignature = $payload['signature'];
unset($payload['signature']);

// rebuild the signature from the payload you received
$expectedSignature = base64_encode(
    openssl_encrypt(
        json_encode($payload),
        'AES-256-CBC',
        $yourPublicKey,
        0,
        $yourSecretKey
    )
);

if (hash_equals($expectedSignature, $receivedSignature)) {
    // signature valid, process the event
    http_response_code(200);
}
PHP · verify
$payload = json_decode($request->getContent(), true);

$signature = $payload['signature'];
unset($payload['signature']);

// decrypt the signature back into the original JSON string
$decrypted = openssl_decrypt(
    base64_decode($signature),   // undo the outer base64 layer
    'AES-256-CBC',
    $yourPublicKey,
    0,                           // options = 0, openssl expects base64 input
    $yourSecretKey
);

if ($decrypted === json_encode($payload)) {
    // signature valid, process the event
    http_response_code(200);
}
Webhooks
POST Sent to your configured webhook URL

Topup Webhooks

Every time a top-up order's status changes, eGiftly sends a webhook to the same webhook URL configured on your account used for Code Webhooks — same delivery, retry, and AES-256-CBC signature mechanism, just a different event namespace and payload shape. Unlike Code Webhooks (one event per code), a single top-up order can generate several events as it moves through the pipeline — e.g. topup.pending → topup.processing → topup.completed — so expect more than one call per topupOrderId and always key off status, not just receipt of an event.

Events

EventOrder statusMeaning
topup.pendingpendingOrder created, wallet not yet charged
topup.processingprocessingWallet charged, purchase submitted to the supplier
topup.completedcompletedSupplier confirmed the top-up was delivered
topup.failedfailedThe purchase failed — see failureReason
topup.refundedrefundedThe charge was reversed back to your wallet
topup.unknownunknownThe supplier request timed out or failed to respond — outcome undetermined, held for reconciliation

Payload fields

FieldTypeDescription
eventstringOne of the events listed above
eventReferenceintegerUnique reference for this event — use it to deduplicate retries
topupOrderIdintegereGiftly top-up order ID (same as id in Create Topup / Topup Status)
vendorOrderUniqueIdstringThe customer_reference you sent when creating the top-up
denominationIdintegerTop-up denomination ID that was purchased
statusstringCurrent order status — same values as data.status in Topup Status
pricenumberAmount charged to your wallet for this order
currencystringISO currency code
failureReasonstring|nullPresent only on topup.failed / topup.unknown. A fixed, generic message — it never includes internal or supplier-specific error text
completedAtstring|nullCompletion timestamp, or null until resolved
datestringEvent timestamp (ISO 8601)
signaturestringSame AES-256-CBC signature scheme as Code Webhooks — see Verifying the Signature
Verification code is identical to Code Webhooks — reuse the PHP generate/verify snippets above as-is; only the payload fields differ.
Payload
{
  "event": "topup.completed",
  "eventReference": 15201,
  "topupOrderId": 9001,
  "vendorOrderUniqueId": "CUST-TOPUP-001",
  "denominationId": 301,
  "status": "completed",
  "price": 10.49,
  "currency": "USD",
  "failureReason": null,
  "completedAt": "2026-08-20T14:20:42.000000Z",
  "date": "2026-08-20T14:20:42.000000Z",
  "signature": "b64EncodedSignatureString=="
}
Payload
{
  "event": "topup.failed",
  "eventReference": 15202,
  "topupOrderId": 9002,
  "vendorOrderUniqueId": "CUST-TOPUP-002",
  "denominationId": 301,
  "status": "failed",
  "price": 10.49,
  "currency": "USD",
  "failureReason": "The top-up request could not be completed.",
  "completedAt": null,
  "date": "2026-08-20T14:22:10.000000Z",
  "signature": "b64EncodedSignatureString=="
}
Payload
{
  "event": "topup.processing",
  "eventReference": 15200,
  "topupOrderId": 9001,
  "vendorOrderUniqueId": "CUST-TOPUP-001",
  "denominationId": 301,
  "status": "processing",
  "price": 10.49,
  "currency": "USD",
  "failureReason": null,
  "completedAt": null,
  "date": "2026-08-20T14:20:05.000000Z",
  "signature": "b64EncodedSignatureString=="
}
Webhooks
POST Sent to your configured webhook URL

Range Webhooks

A range order's code is delivered via the same order.code.ready / order.code.refunded events as Code Webhooks — same webhook URL, delivery, retry, and AES-256-CBC signature mechanism. The payload shape differs in two ways worth knowing before you write a handler that expects a fixed-denomination order: orderId and eventReference are the opaque range order id (e.g. RG-20260909162409HU56), and the code/refund object carries denominationCode (the opaque range denomination code) instead of a raw denominationId.

Payload fields

FieldTypeDescription
eventstringorder.code.ready or order.code.refunded
eventReferencestringSame value as orderId below — use it to deduplicate retries
orderIdstringOpaque range order ID (same as orderId in Create Range Order / Range Order Status)
vendorOrderUniqueIdstringThe uniqueOrderId you sent when creating the order
code.denominationCodestringOpaque range denomination code (same as code in Range Denominations) — present on order.code.ready, under refund instead on order.code.refunded
code.codestringThe redeemable voucher code — only on order.code.ready
refund.refundedAmountnumberAmount refunded to your wallet — only on order.code.refunded
pendingCodesRemainingintegerAlways 0 for range orders — one order produces exactly one code
datestringEvent timestamp (ISO 8601)
signaturestringSame AES-256-CBC signature scheme as Code Webhooks — see Verifying the Signature
Delivery, retries, and signature verification are identical to Code Webhooks — reuse the PHP generate/verify snippets above as-is; only the payload fields differ.
Payload
{
  "event": "order.code.ready",
  "eventReference": "RG-20260909162409HU56",
  "orderId": "RG-20260909162409HU56",
  "vendorOrderUniqueId": "CUST-RANGE-001",
  "code": {
    "brandName": "Binance",
    "brandId": 103,
    "denominationName": "Binance 1 - 500 USDT Open Amount",
    "denominationCode": "RD-1MUZNII9",
    "code": "BMD49AHC7WX8EV66",
    "serialNumber": "",
    "expiryDate": null,
    "createdAt": "2026-09-09T16:24:45.000000Z"
  },
  "pendingCodesRemaining": 0,
  "date": "2026-09-09T16:24:45.000000Z",
  "signature": "b64EncodedSignatureString=="
}
Payload
{
  "event": "order.code.refunded",
  "eventReference": "RG-20260909162409HU56",
  "orderId": "RG-20260909162409HU56",
  "vendorOrderUniqueId": "CUST-RANGE-001",
  "refund": {
    "brandName": "Binance",
    "brandId": 103,
    "denominationName": "Binance 1 - 500 USDT Open Amount",
    "denominationCode": "RD-1MUZNII9",
    "refundedAmount": 10.40,
    "orderFullyRefunded": true
  },
  "pendingCodesRemaining": 0,
  "date": "2026-09-09T16:24:45.000000Z",
  "signature": "b64EncodedSignatureString=="
}