Examples
Billing — Examples
Copy-paste, working requests. BASE = https://<workspace>.corteksa.com/api/v1,
JWT = your user login token. Billing endpoints use the user JWT and require
an active workspace.
Fetch the plan catalog
curl "$BASE/admin/pricing/plans" \
-H "Authorization: Bearer $JWT"Use each plan's slug as the plan_slug below.
Fetch current plan + usage
GET /usage is the single source of truth for the billing screen (subscription
state, per-metric limits/used/remaining, add-ons, pack balances).
curl "$BASE/user/billing/usage" \
-H "Authorization: Bearer $JWT"const res = await fetch(`${BASE}/user/billing/usage`, {
headers: { Authorization: `Bearer ${jwt}` },
});
const { subscription, metrics } = await res.json();Start checkout / add a card (opens Paymob)
POST /checkout is the only endpoint that returns a Paymob
redirect_url. Send the browser there; after Paymob returns, poll /usage.
curl -X POST "$BASE/user/billing/checkout" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{ "callback_url": "https://app.example.com/settings/billing" }'
# → { "data": { "redirect_url": "https://checkout.paymob.com/…" } }const { data } = await (await fetch(`${BASE}/user/billing/checkout`, {
method: 'POST',
headers: { Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ callback_url: `${origin}/settings/billing` }),
})).json();
window.location.href = data.redirect_url; // Paymob hosted page (card + 3DS)On your callback page, confirm the outcome then poll /usage:
curl "$BASE/user/billing/payment-status?payment_id=chg_xxx" -H "Authorization: Bearer $JWT"Change plan / upgrade
POST /change-plan never opens Paymob. On a trial it's a free swap; on an
active subscription an upgrade is charged to the saved card (charged:true) —
then poll /usage until the new plan shows.
curl -X POST "$BASE/user/billing/change-plan" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{ "plan_slug": "advanced", "period": "monthly" }'const { data } = await (await fetch(`${BASE}/user/billing/change-plan`, {
method: 'POST',
headers: { Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ plan_slug: 'advanced' }),
})).json();
if (data.charged) pollUsage(); // active upgrade → new plan lands on the webhookPurchase an add-on
Requires status:"active" + has_payment_method:true (check /usage first).
curl -X POST "$BASE/user/billing/addons" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{ "addon_slug": "whatsapp-session", "quantity": 1 }'Recurring → applied now (redirect_url:null); one-time pack → may return a
redirect_url (handle like a checkout).
List invoices
curl "$BASE/user/billing/invoices?page=1&limit=50" -H "Authorization: Bearer $JWT"Live usage updates (no polling for metered spend)
AI-credit and workflow-execution balances update live over the /data/events
socket — see Events.
import { io } from 'socket.io-client';
const socket = io(`${WS_HOST}/data/events`, { auth: { token: jwt } });
socket.on('usage:updated', (e) => {
// e = { metric, charged, remaining } — render e.remaining directly
setUsage(e.metric, e.remaining);
});More end-to-end flows (recover a past_due workspace, change card while active) are in Frontend Integration.