Getting Started
From an API key to your first fulfilled order in three calls — find, order, reveal.
The Xegora Integration API is the machine-to-machine surface of your merchant workspace: browse the digital-goods catalog, lock a price, place an order against your prefunded wallet, and reveal the delivered codes. This page takes you from zero to your first fulfilled order.
Base URL
https://myapi.xegora.com
Every endpoint is versioned under /api/v1. All requests and responses are JSON over HTTPS; plain HTTP is not served.
Conventions
- Field names are camelCase. Request bodies must contain only the members an endpoint documents: an unknown or misspelt member is refused with
400 invalid_request, and the problem'serrorsmap names it (see Errors & Retries). - Amounts are JSON numbers in the currency named beside them. The number of decimal places carries no meaning —
52.5,52.50and52.50000000are the same amount — so parse amounts as decimals, never as binary floating point. - Timestamps are ISO 8601 instants in UTC with an explicit offset, for example
2026-09-05T12:01:02+00:00or2026-09-05T12:01:02.4817351+00:00(fractional seconds appear when the instant has them). In query parameters sendZor an offset; URL-encode a+as%2B. - Identifiers are opaque. Resource ids are UUIDs; public references carry a prefix and 32 lowercase hex characters (
ord_…orders,wdr_…withdrawals,pdest_…payout destinations,adj_…wallet adjustments,img_…images). - Correlation: send an
X-Correlation-Idheader (1–128 characters ofA–Z a–z 0–9 . _ : -) to have your own id carried through our logs; anything else is replaced by an id of ours. Every response returns the id in its ownX-Correlation-Idheader — errors included — and every error names it again incorrelationId.
The mental model
| Concept | What it is |
|---|---|
| Workspace | Your merchant tenant. Every API key belongs to exactly one workspace, and every resource you can see or create is scoped to it. You never pass a workspace id — it is derived from the key. GET /api/v1/workspace describes it. |
| Wallet | Your workspace's prefunded balance, one per currency. Orders reserve and spend from it; deposits credit it; withdrawals return unused funds to you. Every movement is listed on its statement. |
| Product | A sellable catalog item — a gift card, eSIM, phone top-up, or digital service — with available variants (e.g. a $25 / $50 / $100 card), a default face value, or an amount of your choosing within a range. Denomination currency can differ from the wallet settlement sellCurrency. |
| Quote | A short-lived, binding price for one product + quantity in your sell currency. Every order is priced by one: a quote you create first, or the one an order call makes itself when you send the item. |
| Order | The purchase itself. Creation is asynchronous: you get 202 Accepted and follow the status until it is fulfilled (or a webhook tells you). |
| Fulfillment | The delivered artifacts (codes, PINs, activation values). Revealed only on demand, over a dedicated endpoint, and never included in order bodies or webhooks. |
Get an API key
API keys are issued from the merchant dashboard, never over the API:
- Sign in to your merchant dashboard and open Developers.
- Create a key, choosing only the scopes the integration needs (see Authentication for the scope catalog).
- Copy the plaintext key — it starts with
xeg_live_and is shown once. Xegora authenticates it by a hash; it cannot show you the key again.
Send the key on every request in the X-Api-Key header:
curl https://myapi.xegora.com/api/v1/me \
-H "X-Api-Key: xeg_live_AbCdEfGhIjKl.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"GET /api/v1/me answers with the key itself — its scopes and expiry, never its secret — and is a good first call for a deployment check:
{
"keyId": "0198d6f1-2c3b-7d4e-8f5a-6b7c8d9e0f1a",
"name": "Order service",
"prefix": "xeg_live_AbCdEfGhIjKl",
"scopes": ["orders.create", "orders.read"],
"expiresAtUtc": null,
"allowedCidrCount": 1,
"workspaceId": "0198d6a0-1b2c-7d3e-8f4a-5b6c7d8e9f0a"
}GET /api/v1/workspace (any key) tells you where the workspace stands: its currencies, whether its API access is active and paid through when, its plan, and its request budget. It also reports the limits the workspace's orders and withdrawals are held to — but only to a key holding wallet.read; to any other key limits is null.
GET /api/v1/workspace/overview (any key) draws the whole picture in one call: how many products the workspace can sell, what each of its wallets holds, its newest deposits, and what it has bought over the last thirty days (?salesDays= takes 1 to 92). Nothing in it is a new fact — each section is the same figure its own endpoint serves — so use it to paint a dashboard without five round trips. Each section is behind its own scope and comes back null when the key may not read it: catalog needs products.read, wallets and deposits need wallet.read, sales needs orders.read. A null section means "this key may not see it"; an empty list means "there is none".
Your first order, end to end
The purchase flow is three calls: find → order → reveal. The order call prices the item itself
and can refuse a price above the ceiling you set. When you want to show a buyer a locked price
before they commit, add a quote in between: find → quote → order → reveal.
1. Find a product (products.read)
products.read)curl "https://myapi.xegora.com/api/v1/products?productType=gift-card&query=game&countryCode=US&limit=10" \
-H "X-Api-Key: $XEGORA_API_KEY"{
"items": [
{
"id": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"type": "gift-card",
"name": "Everyday Digital Gift Card",
"countryCode": "US",
"currency": "USD",
"imageUrl": "/api/v1/catalog-product-images/img_5f4e3d2c1b0a99887766554433221100",
"isAvailable": true,
"variants": [
{ "id": "0198d72d-a15b-7cbf-ab69-b95410e98636", "displayValue": "$50", "price": 52.50, "currency": "USD", "faceValue": 50.00, "attributes": null }
],
"category": "department-stores",
"sellCurrency": "USD",
"faceValue": null,
"priceFrom": 52.50,
"priceTo": 52.50,
"customAmount": null,
"publicCategories": [{ "key": "department-stores", "title": "Department Stores" }]
}
],
"offset": 0,
"limit": 10,
"hasMore": false
}The product above is abridged; Catalog lists every field. Choose a variant by id, or choose a value supported by the product's customAmount range or default faceValue. Supply only one selection style. faceValue is the amount the product represents, not its purchase price; a variant price is an indicative price in sellCurrency, and null means no indicative price can be shown. Treat every id and image reference as opaque.
To build navigation, call GET /api/v1/categories for the public categories your catalog fills, and GET /api/v1/products/filters for product types, countries, categories, and denomination currencies with product counts. Once you know which products you sell, refresh exactly those with GET /api/v1/products?ids=… — up to 100 in one call. See Catalog for every filter, sorting, pagination, and count semantics.
2. Order it (orders.create)
orders.create)Order creation requires an Idempotency-Key header — a value you generate (1–128 printable characters) that makes retries safe. Sending the same key again returns the same order instead of buying twice.
Send the item itself: the call prices it now and orders it at that price. maximumTotal is optional and caps what you accept to pay — a higher price orders nothing and tells you what the price is. Use the product's sellCurrency as currency.
curl -X POST https://myapi.xegora.com/api/v1/orders \
-H "X-Api-Key: $XEGORA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-09-05-000123" \
-d '{
"clientReference": "your-order-1001",
"item": {
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"quantity": 1,
"currency": "USD"
},
"maximumTotal": 55.00
}'HTTP/1.1 202 Accepted
Location: /api/v1/orders/0198e000-1111-7abc-9def-222233334444
{
"id": "0198e000-1111-7abc-9def-222233334444",
"clientReference": "your-order-1001",
"status": "reserved",
"total": 52.50,
"currency": "USD",
"createdAtUtc": "2026-09-05T12:01:02+00:00",
"updatedAtUtc": "2026-09-05T12:01:02+00:00",
"lines": [
{
"productName": "Everyday Digital Gift Card",
"variantLabel": "$50",
"quantity": 1,
"unitPrice": 52.50,
"currency": "USD",
"faceValue": 50.00,
"faceCurrency": "USD",
"requestedValue": null,
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"lineTotal": 52.50
}
],
"publicReference": "ord_0198e00011117abc9def222233334444",
"completedAtUtc": null,
"statusReason": null,
"refund": null
}202 Accepted means the order was admitted and your wallet funds are reserved — fulfillment happens asynchronously, usually within seconds. Follow it with GET /api/v1/orders/{orderId} or let a webhook push the outcome to you (see Webhooks).
Or: show a locked price first (quotes.create)
quotes.create)When a buyer should see the exact total before committing, quote first and order against the quote. Use the selected product's sellCurrency as the quote's currency, even when its denomination currency differs.
curl -X POST https://myapi.xegora.com/api/v1/quotes \
-H "X-Api-Key: $XEGORA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"value": null,
"quantity": 1,
"currency": "USD"
}'{
"id": "0198d72d-a6ce-77c6-9586-fc36708731d0",
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"quantity": 1,
"total": 52.50,
"currency": "USD",
"expiresAtUtc": "2026-09-05T12:05:00+00:00",
"unitPrice": 52.50,
"productName": "Everyday Digital Gift Card",
"variantLabel": "$50",
"faceValue": 50.00,
"faceCurrency": "USD",
"requestedValue": null,
"status": "active"
}The total is exactly what the order will debit from your wallet. Quotes expire after a few minutes; an expired quote is rejected at order time, so quote close to the moment of purchase. Then order against it:
curl -X POST https://myapi.xegora.com/api/v1/orders \
-H "X-Api-Key: $XEGORA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-09-05-000123" \
-d '{
"quoteId": "0198d72d-a6ce-77c6-9586-fc36708731d0",
"clientReference": "your-order-1001"
}'The response is the same 202 Accepted order.
3. Reveal the delivered codes (orders.reveal or orders.create)
orders.reveal or orders.create)Once the order is fulfilled:
curl -X POST https://myapi.xegora.com/api/v1/orders/0198e000-1111-7abc-9def-222233334444/fulfillment \
-H "X-Api-Key: $XEGORA_API_KEY" \
-H "Idempotency-Key: reveal-your-order-1001"{
"orderId": "0198e000-1111-7abc-9def-222233334444",
"revealCount": 1,
"artifacts": [
{ "type": "code", "value": "XXXX-XXXX-XXXX-XXXX", "expiresAtUtc": null }
],
"revealLimit": 10,
"remainingReveals": 9
}Every reveal is counted and audited, and an order's codes can be revealed only a limited number of times; the response is delivered with Cache-Control: no-store. A key with only orders.read cannot reveal. Treat artifact values like passwords — see Fulfillment.
Funding the wallet
Orders debit your prefunded wallet. Check it any time:
curl "https://myapi.xegora.com/api/v1/wallet/balance?currency=USD" \
-H "X-Api-Key: $XEGORA_API_KEY"To top it up, list the deposit options (GET /api/v1/wallet/deposit-options), request your workspace's permanent deposit address for one of the networks and stablecoins it lists, and send that stablecoin to it on that network; confirmed deposits credit the wallet automatically, less the option's deposit fee (feePercent). GET /api/v1/wallet/movements is the wallet's statement: every credit, hold and debit with the balance it left behind. The whole flow is covered in Wallet & Deposits.
Errors, correlation, and support
Failures return an RFC 9457 problem document (application/problem+json) with a stable machine code, a correlationId, and a message in the language you asked for:
{
"title": "The request could not be completed.",
"status": 404,
"detail": "Use the error code and correlation ID when contacting support.",
"code": "not_found",
"correlationId": "0198e001a2b37c4d8e9f0a1b2c3d4e5f",
"message": "That could not be found. It may have been removed."
}Branch on code, never on the wording. Always log the correlationId; quoting it lets support trace the exact request. The full error model, every code, retry rules, and the request budgets (120 requests per minute per workspace) are in Errors & Retries.
Where to next
- Authentication — scopes, access standing, network allow-lists, key hygiene.
- Catalog — discovery filters and counts, pagination, denominations, settlement currencies, and images.
- Quotes
- Orders — idempotency, the status lifecycle, history, and list filters.
- Fulfillment
- Wallet & Deposits — balances, the statement, deposits.
- Withdrawals
- Webhooks
- Errors & Retries
- Go-Live Checklist
Updated 18 days ago