For production client patterns in TypeScript, Python, PHP, Go, Java, and C#, see API clients and Architecture patterns. Multi-language tabs on this site remember your last language choice.
Example#
# Prefer env vars — never hardcode secrets in source control
export AVRIX_API_KEY="avrix_sk_sbx_your_key_here"
export AVRIX_BASE_URL="https://api.avrix.io"Generating a typed client#
The OpenAPI document is the contract, and it is served live by your API host:
- Interactive docs:
https://api.avrix.io/api/seller/v1/docs - OpenAPI JSON download:
https://api.avrix.io/api/seller/v1/openapi
Point any OpenAPI generator at that JSON to produce a typed client in your
language of choice, and regenerate whenever info.version changes. Generated
clients inherit the same X-Api-Version compatibility policy as the raw API —
see Versioning and compatibility.
Postman#
Avrix provides a ready-made Seller API Postman collection for manual exploration.
Import it into Postman, point the environment baseUrl at https://api.avrix.io,
and set apiKey to the raw key only (the collection adds the Bearer prefix).
Use a sandbox key for everyday testing and a production key only after go-live.
Ask your Avrix contact if you need the collection file or a shared workspace copy.
When to generate a client vs use fetch#
| Approach | Best for |
|---|---|
| Generated client | Large integrations, typed requests, refactors |
Raw fetch or Postman | Quick tests, minimal dependencies, other languages |
Both are valid; the contract is always GET /api/seller/v1/openapi.
Behaviours a production client needs#
Whether you generate a client or use fetch, implement these behaviours:
| Behaviour | Why |
|---|---|
Retry on 429 / 502 / 503 / 504 | Honour Retry-After with backoff |
Stable Idempotency-Key on writes | Prevents duplicate fulfilment on retries — Idempotency |
| Webhook signature verification | HMAC-SHA256 on the raw body — Webhooks |
| Catalog sync = snapshot + allocations | Shared SKUs alone are not the sellable set — Catalog and allocations |
| Preview before charge | Gate on canFulfill — Order preview |
HTTP patterns (copy-paste)#
Authenticated request with retries#
async function sellerFetch(
path: string,
init: RequestInit & { idempotencyKey?: string } = {},
): Promise<Response> {
const headers = new Headers(init.headers);
headers.set("Authorization", `Bearer ${apiKey}`);
if (init.idempotencyKey) headers.set("Idempotency-Key", init.idempotencyKey);
if (init.body && !headers.has("Content-Type")) {
headers.set("Content-Type", "application/json");
}
let attempt = 0;
while (true) {
const res = await fetch(`https://api.avrix.io${path}`, { ...init, headers });
if (res.status !== 429 && res.status < 500) return res;
attempt += 1;
if (attempt > 5) return res;
const retryAfter = Number(res.headers.get("Retry-After") ?? "1");
await new Promise((r) => setTimeout(r, Math.min(30, retryAfter) * 1000));
}
}
await sellerFetch("/api/seller/v1/whoami");
Preview → charge → order#
const previewRes = await sellerFetch("/api/seller/v1/orders/preview", {
method: "POST",
body: JSON.stringify({
skuCode: "SANDBOX-ALWAYS-001",
quantity: 1,
countryCode: "US",
}),
});
const previewJson = await previewRes.json();
if (!previewJson.data?.canFulfill) {
throw new Error("Do not charge — Avrix cannot fulfil");
}
// Charge at your PSP, then:
const orderRes = await sellerFetch("/api/seller/v1/orders", {
method: "POST",
idempotencyKey: "ik_store_10432",
body: JSON.stringify({
skuCode: "SANDBOX-ALWAYS-001",
quantity: 1,
orderReference: "store-order-10432",
countryCode: "US",
expectedUnitPriceCents: previewJson.data.unitPriceCents,
priceCommitmentToken: previewJson.data.priceCommitmentToken,
integrationOrderContext: {
schemaVersion: 1,
salesCountryCode: "US",
currencyCode: "USD",
salesPriceGrossMinor: 1999,
salesPriceNetMinor: 1999,
priceIncludesTax: true,
salesTaxAmountMinor: 0,
salesTaxRatePercent: 0,
salesChannel: "web",
consumerIp: "203.0.113.42",
paymentMethodFamily: "card",
paymentProcessorReference: "psp_txn_10432",
checkoutSessionId: "cs_store_10432",
},
}),
});
Catalog sync (HTTP algorithm)#
- Page through GET /catalog/snapshot (or GET /products).
- Page through GET /allocations and merge on SKU id — authoritative
sellable. - Persist a watermark and call
GET /catalog/changes?since=for deltas (including tombstones).
Never treat /products alone as the sellable catalog.
Related#
- Quickstart — golden path using raw
fetchor a generated client - Integration recipes — scopes, call order, and idempotency per flow
- Webhooks — signature verification and delivery semantics
- Partner runbook — keep OpenAPI and client artifacts in sync