Corteksa
GuidesBilling

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 webhook

Purchase 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.

On this page