Concepts
Key ideas you need before integrating: base URL, item codes, price vs face value (charged vs denomination), the response envelope, and the difference between checking stock and checking order status.
Base URL and versioning
All API requests go to:
https://api.cardpluspay.com/v1
The path /v1 is the API version. Append the endpoint path to this base (e.g. https://api.cardpluspay.com/v1/balance, https://api.cardpluspay.com/v1/catalog). Future versions may use /v2; the current production version is v1.
Item codes
Products in the catalog are identified by an item code (sometimes referred to as item_id in query parameters). For example: GOOGLE-5USD-KOXx.
- Use the same identifier when calling the catalog, checking stock, and creating orders.
- Get item codes from
GET /catalogorGET /catalog?item_id=...; store the code in your database or config when you link your products to CardPlusPay.
Price vs face value (list, charged, denomination)
Three kinds of amounts appear in catalog and order responses. Use them correctly:
- Face value (denomination) — What the customer receives (e.g. “$5 Google Play card” or “60 UC”). In the catalog use face_value (preferred) or value (alias). In order responses use denomination per code. For display only — not for billing.
- List price — Pre-offer wholesale/list price per unit. In the catalog this is price.
- Charged amount — What is debited per unit after an active offer. In the catalog this is charged_price (equals
pricewhen no offer). In stock check and orders use price / charged_amount / amount for financial logic.
Always re-check at checkout: cache charged_price from the catalog for display, but call POST /orders/check for the authoritative per-unit charge and stock before purchase.
Charged amount can be less than face value (e.g. promotional pricing). Never use face value for balance or checkout totals.
Product type vs category
category is a merchandising shelf (e.g. “Google Play SA”). Path GET /catalog/{category} filters by category.
product_type is the product vertical (e.g. app_store, game_card, direct_top_up). Filter with ?product_type= on GET /catalog. See the display products guide for the full slug list.
Response envelope
Every API response uses a common structure:
{
"success": true | false,
"message": "Human-readable message",
"data": { ... }
}
- success — Whether the request succeeded. Always check this before trusting
data. - message — Short description (e.g. "Balance retrieved successfully" or an error message).
- data — The payload. Structure depends on the endpoint (e.g.
balance,products,order_id,codes).
On failure, success is false and message (and optionally data) describes the error.
Purchase and delivery
Gift card and digital product purchases are fulfilled through the CardPlusPay API. Your integration uses CardPlusPay endpoints only.
- Code delivery — Products such as
game_card,gift_card, andapp_storereturn redeemablecodesin thePOST /ordersresponse when fulfillment completes in the same request. - Direct top-up — Products with
product_type = direct_top_upcredit a buyer account. They require afieldsobject (from catalogrequired_fields), return emptycodes, and include adeliveryobject. See direct top-up orders. - Async fulfillment — Some orders return HTTP 200 with
status: pending(and emptycodesfor code products). This means CardPlusPay is still processing — not a failure. PollGET /orders/{id}untilcompletedorfailed. Your API wallet stays debited while an order ispending. - Availability —
available_quantityonPOST /orders/checkreflects how many units CardPlusPay can fulfill right now. It may change between check and purchase; always re-validate at checkout. - Order lookup — Use
GET /orders/{id}after create when status ispending, after a connection timeout, or for support — see order status & polling.
Stock check vs order status
Do not confuse these two operations:
| Goal | Endpoint | Use when |
|---|---|---|
| Check if a product is available (stock) | POST /orders/check |
Before add-to-cart or checkout. Send item_id (item code) and quantity. Response tells you if that quantity is in stock. |
| Get status of an existing order | GET /orders/{id} |
After creating an order. Send the order_id from the create response. Use this to show status and retrieve gift card codes. |
Use POST /orders/check for “Is this product in stock?” and GET /orders/{id} for “What’s the status of order #123?”
Quantity limits
CardPlusPay exposes per-SKU quantity limits so you can cap cart and checkout without guessing:
- Catalog (
GET /catalog) — Each product includesmin_quantityandmax_quantityfor listings and sync. These are not live stock counts. - Stock check (
POST /orders/check) — Successdataaddsavailable_quantity(units purchasable now, ornullif unknown), plusquantity_contract_version(currently1). - Purchase (
POST /orders) — Quantity must be within the SKU min/max and current stock. Failures usedata.stateofinvalid_quantityorout_of_stock.
Purchasable cap (client-side):
purchasable_now = min(max_quantity, available_quantity ?? max_quantity, 100)
Also apply your wallet: floor(balance / price) from GET /balance. See the check availability guide for a full example response.
Typical purchase flow
A common end-to-end flow for buying a gift card looks like this:
- Check balance — Optional but recommended. Call
GET /balanceto ensure you have enough funds for the planned purchase. - Get product info — Use
GET /catalog(orGET /catalog?item_id=...) foritem_code,charged_price, face value, quantity bounds, andproduct_type. Paginate withsort_by=item_codefor full sync. - Check stock and price — Before checkout, call
POST /orders/checkwithitem_idandquantity. Usedata.price(authoritative charge),min_quantity,max_quantity, andavailable_quantity; confirmstateis"in_stock". - Create the order — After payment is authorized, call
POST /orderswithitem_codeandquantity(and a stableIdempotency-Keyin production). Fordirect_top_upSKUs, includefields— see direct top-up orders. On success, useorder_id,amount, and eithercodes(code products) ordelivery.status(top-up). - Poll if pending — When
statusispending, callGET /orders/{id}on an interval untilcompletedorfailed. Do not treat a client timeout as failure — retryPOST /orderswith the same idempotency key first. - Confirm if needed (optional) — Call
GET /orders/{id}if you did not receive a response and are reconciling with the same idempotency key, or for support.