A minimal REST surface. Bearer-key auth, HMAC-signed webhooks, sandbox environment for testing before you commit real balance.
https://kwxdkuljhwdbwqvzdgpw.supabase.co/functions/v1/X-Sandbox: true. All calls succeed but no real credit is minted and no email is sent.All API calls require the header x-org-api-key with a key we issue when your account is provisioned. Keys are rotatable from the admin surface. Losing a key does not lose funded balance — rotate and the previous key is immediately invalidated.
curl -sS https://kwxdkuljhwdbwqvzdgpw.supabase.co/functions/v1/org-issue-credits \
-H "x-org-api-key: $YOUR_ORG_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipient_email": "student@example.edu",
"amount_cents": 5000,
"metadata": {"cohort": "fall-2026", "program": "cs-101"}
}'
Deducts amount_cents from your funded balance, mints an access card, emails the recipient.
Request body:
{
"recipient_email": "string, required, valid email",
"amount_cents": "integer, required, min 1000 (=$10), max 100000 (=$1000)",
"metadata": "object, optional, key/value pairs echoed on ledger and webhook",
"expires_days": "integer, optional, default 1825 (5 years), max 1825"
}
Response (200):
{
"success": true,
"card_id": "uuid",
"card_code": "AIG-XXXX-XXXX-XXXX",
"redemption_url": "https://youraiaccess.com/redeem.html?c=...",
"expires_at": "2031-08-11T00:00:00Z",
"balance_remaining_cents": 4950000
}
Error responses:
401 — missing or invalid x-org-api-key402 — insufficient funded balance422 — validation error (email invalid, amount out of range)429 — rate limit exceeded (see below)Returns your current funded balance, committed balance (pending redemptions), and used balance.
{
"balance_cents": 4950000,
"committed_cents": 250000,
"used_cents": 800000,
"last_topup_at": "2026-08-01T14:22:11Z"
}
Returns the audit event stream for your org since the given ISO timestamp. Paginated at 200 events per page. Useful for warm-start recovery if you missed webhook deliveries.
Configure a single webhook URL from the admin surface. We POST JSON to it for every credit lifecycle event. Every request carries an X-Signature header — a lowercase-hex HMAC-SHA256 of the raw request body, signed with your webhook secret.
Verify the signature before trusting the payload. Sample (Node):
const crypto = require('crypto');
function verify(rawBody, secret, signature){
const expected = crypto.createHmac('sha256', secret)
.update(rawBody, 'utf8').digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(signature, 'hex')
);
}
{
"event": "credit.issued",
"event_id": "uuid",
"created_at": "2026-08-11T18:00:00Z",
"data": {
"card_id": "uuid",
"card_code": "AIG-...",
"recipient_email": "student@example.edu",
"amount_cents": 5000,
"metadata": {"cohort":"fall-2026"}
}
}
{
"event": "credit.redeemed",
"event_id": "uuid",
"created_at": "2026-08-14T09:12:33Z",
"data": {
"card_id": "uuid",
"card_code": "AIG-...",
"provider_id": "uuid",
"provider_name": "ChatGPT",
"amount_redeemed_cents": 2000,
"remaining_cents": 3000,
"recipient_email": "student@example.edu"
}
}
{
"event": "credit.expired",
"event_id": "uuid",
"created_at": "2031-08-11T00:00:00Z",
"data": {
"card_id": "uuid",
"card_code": "AIG-...",
"unredeemed_cents": 3000
}
}
We retry failed deliveries with exponential backoff — 3 attempts total, at 30s, 5min, and 30min after the first failure. Any 2xx response is treated as success. After the third failure we mark the event as delivery_failed and surface it in the org admin dashboard. Use GET /org-events to replay.
Exceeding a limit returns HTTP 429 with a Retry-After header (seconds).
Pass an Idempotency-Key header (any string ≤ 128 chars) to make issuance safely retryable. Repeats within 24 hours return the original response without re-issuing the card.
Add X-Sandbox: true to any call. Sandbox mode:
card_id prefixed sbx-data.sandbox: trueFor integration help: bill@bdsrvs.com. We respond within 1 business day and can jump on a call for onboarding of accounts $10K+.