REST endpoints to create storefronts, manage products, read orders, and run AI generation jobs from your own code or scripts. Production base URL: https://api.instxnt.xyz.
All requests require a session cookie (set after login) plus a short-lived CSRF token in the X-CSRF-Token header for any mutating request (POST, PATCH, DELETE).
curl -s https://api.instxnt.xyz/api/auth/csrf \
-H "Cookie: $YOUR_SESSION_COOKIE"
# → { "token": "csrf_..." }curl -X POST https://api.instxnt.xyz/api/stores \
-H "Content-Type: application/json" \
-H "Cookie: $YOUR_SESSION_COOKIE" \
-H "X-CSRF-Token: csrf_..." \
-d '{"name":"Test Store","slug":"test-store"}'Sessions are tied to your account. For programmatic access, log in once via the dashboard, copy the session cookie out of your browser's devtools, and paste into your script. Long-lived API tokens for headless automation are available on Pro — contact support@instxnt.xyz to request one.
A "store" is a single-product storefront. Each owner can have unlimited stores on every plan.
GET /api/stores
# → { "stores": [ { "id": "st_...", "name": "...", "subdomain": "...", "status": "live" }, ... ] }POST /api/stores
{
"name": "Magnetic phone mount",
"subdomain": "phone-mount-test" // optional; auto-generated if omitted
}
# → 201 { "id": "st_abc123", "subdomain": "phone-mount-test", "url": "https://phone-mount-test.instxnt.store", "status": "draft" }PATCH /api/stores/st_abc123
{
"settings": {
"theme": "neon",
"primary_color": "#0066ff",
"ad_pixels": { "meta": "1234567890", "tiktok": "C7..." }
}
}DELETE /api/stores/st_abc123
# → 204 No ContentSoft-deleted stores are hidden but recoverable for 30 days. After 30 days they're hard-deleted along with their R2 image objects.
Each storefront has one primary product. Products carry pricing, variants, descriptions, and digital-download payloads.
GET /api/stores/st_abc123/product
# → { "id": "pr_...", "title": "...", "price_cents": 2999, "currency": "USD", "variants": [...] }PATCH /api/stores/st_abc123/product
{
"title": "Magnetic Phone Mount for Cars",
"price_cents": 2400,
"description_html": "<p>Stays put...</p>",
"faq": [
{"q": "Will it fit my phone?", "a": "Works with phones up to 6.9\""},
{"q": "How does it stick to the vent?", "a": "Strong magnet + grip..." }
]
}POST /api/images/st_abc123/upload
# Multipart form upload, field name: "image"
# Returns: { "url": "https://images.instxnt.xyz/...", "r2_key": "..." }Kick off a job that generates product copy, FAQ entries, and SEO metadata from a product image plus a few hints. Jobs run async on Cloudflare Queues; poll for status.
POST /api/generate/start
{
"store_id": "st_abc123",
"image_url": "https://images.instxnt.xyz/...",
"hints": {
"product_kind": "kitchen accessory",
"tone": "casual",
"audience": "home cooks"
}
}
# → 202 { "job_id": "jb_xyz789" }GET /api/generate/status/jb_xyz789
# Possible states: queued | running | succeeded | failed
# When succeeded:
# {
# "status": "succeeded",
# "output": {
# "title": "...", "description": "...", "faq": [...],
# "seo": { "title": "...", "description": "...", "keywords": [...] }
# }
# }Free-tier accounts can run 5 generations/day. Pro at $19/mo allows 100/day. Errors fail the job with a structured reason in error.code.
Checkout sessions are created on demand for each buyer. instxnt uses Stripe Connect Express; funds settle to the seller's connected Stripe account, not to instxnt.
POST /api/checkout/create-session
{
"store_id": "st_abc123",
"variant_id": "vr_...", // optional
"quantity": 1,
"success_url": "https://yourstore.instxnt.store/thank-you",
"cancel_url": "https://yourstore.instxnt.store/cart"
}
# → { "session_id": "cs_test_...", "url": "https://checkout.stripe.com/c/pay/..." }Most callers will not need this directly — instxnt's rendered storefronts handle session creation server-side. Use this when you're embedding checkout into a custom flow.
application_fee_amount; sellers see it itemized in their Stripe dashboard.GET /api/stores/st_abc123/orders?limit=50&cursor=...
# Returns paginated:
# {
# "orders": [
# {
# "id": "or_...", "stripe_payment_intent": "pi_...",
# "total_cents": 3000, "currency": "USD",
# "buyer": { "email": "...", "name": "..." },
# "shipping_address": {...},
# "status": "paid" | "fulfilled" | "refunded",
# "created_at": "2026-04-26T..."
# }, ...
# ],
# "next_cursor": "..."
# }GET /api/orders/or_.../api/generate/start.Exceeding any limit returns HTTP 429 with Retry-After in seconds. Burst over the per-minute limits is allowed up to 2× for short windows.
Errors return a JSON body with a stable code field plus a human-readable message. Codes are stable across versions; messages are not.
// 400 Bad Request
{ "code": "validation_failed", "message": "price_cents must be a positive integer", "field": "price_cents" }
// 401 Unauthorized
{ "code": "missing_session", "message": "Authenticate via /api/auth/* first" }
// 403 Forbidden
{ "code": "not_owner", "message": "You do not own store st_abc123" }
// 404 Not Found
{ "code": "not_found", "message": "Store not found" }
// 429 Too Many Requests
{ "code": "rate_limited", "message": "Slow down", "retry_after": 12 }
// 500 Internal
{ "code": "internal", "message": "...", "request_id": "req_..." }Always log request_id when you see a 500. It maps to a single line in our edge logs and is the fastest way to get help on a specific failure.
instxnt fires webhooks for order events (order.paid, order.refunded, order.fulfilled) so your downstream systems stay in sync.
// Create a store, upload an image, kick off AI generation,
// poll until done, and update the product with the result.
const BASE = 'https://api.instxnt.xyz';
const COOKIE = process.env.INSTXNT_SESSION_COOKIE!;
async function api(path: string, init: RequestInit = {}) {
const csrf = await fetch(`${BASE}/api/auth/csrf`, { headers: { Cookie: COOKIE } })
.then(r => r.json())
.then(j => j.token);
return fetch(`${BASE}${path}`, {
...init,
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrf,
Cookie: COOKIE,
...(init.headers || {}),
},
});
}
const store = await api('/api/stores', {
method: 'POST',
body: JSON.stringify({ name: 'Magnetic phone mount' }),
}).then(r => r.json());
const job = await api('/api/generate/start', {
method: 'POST',
body: JSON.stringify({
store_id: store.id,
image_url: 'https://images.instxnt.xyz/uploads/abc.jpg',
hints: { product_kind: 'car accessory', tone: 'casual' },
}),
}).then(r => r.json());
let status: any;
do {
await new Promise(r => setTimeout(r, 2000));
status = await fetch(`${BASE}/api/generate/status/${job.job_id}`, { headers: { Cookie: COOKIE } })
.then(r => r.json());
} while (status.status === 'queued' || status.status === 'running');
if (status.status !== 'succeeded') throw new Error('Generation failed');
await api(`/api/stores/${store.id}/product`, {
method: 'PATCH',
body: JSON.stringify(status.output),
});Spotted something wrong, missing, or out of date?
Email support@instxnt.xyz