API · v2.0.0
Fleet API
For Max, Ulti and anyone else on the fleet: quotes, proposals, invoices, subscriptions and payment links across brands and Stripe accounts, without the UI.
Authentication
Create a token in Settings with a label (for example "Max") and scopes. It is shown once. Send it as a bearer header on every call. Every call is written to the audit log with the token label, endpoint, time and IP.
export KB_TOKEN=kb_... curl https://billing.kyberapps.com/api/v1/me -H "Authorization: Bearer $KB_TOKEN"
Rate limit per token: 60 burst, then 1 request per second. 429 carries Retry-After. Idempotency-Key on POST replays the stored response for 1 key + token + path.
Scopes
| read | List and read everything, including proposal acceptance status. |
| quotes:write | Create and update organizations and quotes; mark quotes sent. |
| proposals:write | Create proposals from quotes, edit them, mark sent. |
| invoices:write | Create Stripe or manual invoices, send, mark paid. |
| subscriptions:write | Create subscriptions from accepted proposals, sync, set brand. |
| links:write | Create and deactivate payment links. |
| admin | Everything, including Stripe account sync. |
Conventions
JSON bodies. Money is integer cents (unit_cents, total_cents); on quote lines you may send unit_price in dollars instead. Dates are YYYY-MM-DD. Timestamps are UTC ISO 8601. Errors are {"error": "..."} with honest status codes: 400, 401, 403, 404, 405, 409, 422, 429, 502, 503.
The whole flow in five calls
ORG=$(curl -s https://billing.kyberapps.com/api/v1/orgs -H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" -d '{"name":"Sample Academy","type":"school","enrollment":900}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
Q=$(curl -s https://billing.kyberapps.com/api/v1/quotes -H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" -d "{\"org_id\":$ORG,\"lines\":[{\"product\":\"KyberCopy\",\"qty\":1}]}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
curl -s -X POST https://billing.kyberapps.com/api/v1/quotes/$Q/send -H "Authorization: Bearer $KB_TOKEN" # share_url for the customer
P=$(curl -s https://billing.kyberapps.com/api/v1/proposals -H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" -d "{\"quote_id\":$Q,\"send\":true}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
curl -s https://billing.kyberapps.com/api/v1/proposals/$P/status -H "Authorization: Bearer $KB_TOKEN" # poll until status=accepted
curl -s https://billing.kyberapps.com/api/v1/invoices -H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" -d "{\"proposal_id\":$P,\"send\":true}"Endpoints
Who am I
Returns the token label and scopes.
curl https://billing.kyberapps.com/api/v1/me -H "Authorization: Bearer $KB_TOKEN"
Pricing rules
The pricing rules as data: KyberCopy bands, KyberGate floor and bands, manual products, multi-year discounts.
curl https://billing.kyberapps.com/api/v1/pricing-rules -H "Authorization: Bearer $KB_TOKEN"
Suggest a line
Default description, unit and unit price for a product. requires_price=true means the price must be supplied manually.
curl https://billing.kyberapps.com/api/v1/pricing-rules/suggest?product=KyberCopy&qty=1&enrollment=900 -H "Authorization: Bearer $KB_TOKEN"
Agreement text
Current Master Subscription Agreement text and version.
curl https://billing.kyberapps.com/api/v1/terms -H "Authorization: Bearer $KB_TOKEN"
List organizations
curl https://billing.kyberapps.com/api/v1/orgs?search= -H "Authorization: Bearer $KB_TOKEN"
Create organization
type is school, district or other. contacts is a list of {name,email,phone,role}. products is a list of product names.
curl -X POST https://billing.kyberapps.com/api/v1/orgs \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name": "Sample Academy", "type": "school", "address": "1 Main St, Albany, NY", "enrollment": 900, "contacts": [{"name": "Dana Lee", "email": "dlee@sample.edu", "phone": "", "role": "IT Director"}], "products": ["KyberCopy"], "tax_exempt": true, "tax_exempt_no": "EX-12345"}'Get organization
Includes the org's quotes, proposals and invoices.
curl https://billing.kyberapps.com/api/v1/orgs/1 -H "Authorization: Bearer $KB_TOKEN"
Update organization
Send only the fields you want to change.
curl -X PATCH https://billing.kyberapps.com/api/v1/orgs/1 \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"enrollment": 1200}'List quotes
status: draft, sent, accepted, expired, declined, converted.
curl https://billing.kyberapps.com/api/v1/quotes?org_id=&status= -H "Authorization: Bearer $KB_TOKEN"
Create quote
Lines: product (KyberGate, KyberAccess, KyberWatch, KyberCopy), description (optional, defaulted), qty, unit, unit_cents or unit_price (dollars), years, term_start, term_end, is_pilot. KyberCopy price is defaulted from the org's enrollment band when unit_cents is omitted. KyberGate never below 500 cents. KyberAccess and KyberWatch need a manual price. discount_type: none, percent (discount_percent, e.g. 10) or fixed (discount_amount in dollars). multi_year_percent: 0, 10 or 15. valid_until defaults to 30 days.
curl -X POST https://billing.kyberapps.com/api/v1/quotes \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"org_id": 1, "lines": [{"product": "KyberCopy", "qty": 1, "term_start": "2026-11-01", "term_end": "2027-10-31"}, {"product": "KyberGate", "qty": 800, "unit_price": "5.50", "description": "KyberGate Basic, per device, annual"}], "discount_type": "percent", "discount_percent": 10, "notes": "Pricing held through the validity date."}'Get quote
Includes share_path (/q/<token>) for the customer-facing page.
curl https://billing.kyberapps.com/api/v1/quotes/1 -H "Authorization: Bearer $KB_TOKEN"
Update quote
Same fields as create. Pass status: declined to decline. Accepted or converted quotes are locked.
curl -X PATCH https://billing.kyberapps.com/api/v1/quotes/1 \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"lines": [{"product": "KyberCopy", "qty": 2, "unit_price": "3600"}]}'Mark quote sent
Sets status=sent and returns share_url. Nothing is emailed; deliver the link yourself.
curl -X POST https://billing.kyberapps.com/api/v1/quotes/1/send \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'Duplicate quote
New draft with a new number.
curl -X POST https://billing.kyberapps.com/api/v1/quotes/1/duplicate \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'List proposals
curl https://billing.kyberapps.com/api/v1/proposals?org_id=&status= -H "Authorization: Bearer $KB_TOKEN"
Create proposal from quote
Snapshots the quote and org, drafts the cover letter, attaches the current agreement text. payment_terms: net30 (PO, Stripe send_invoice) or card (hosted invoice, charge automatically). send: true also marks it sent.
curl -X POST https://billing.kyberapps.com/api/v1/proposals \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"quote_id": 1, "payment_terms": "net30", "po_number": "", "send": true}'Get proposal
Includes share_url and the quote snapshot.
curl https://billing.kyberapps.com/api/v1/proposals/1 -H "Authorization: Bearer $KB_TOKEN"
Proposal status
Acceptance details: accepted_name, accepted_title, accepted_email, accepted_at (UTC), accepted_ip.
curl https://billing.kyberapps.com/api/v1/proposals/1/status -H "Authorization: Bearer $KB_TOKEN"
Update proposal
cover_letter, payment_terms, po_number, term_start, term_end, status (sent/declined). Locked after acceptance.
curl -X PATCH https://billing.kyberapps.com/api/v1/proposals/1 \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"po_number": "PO-2026-118"}'Mark proposal sent
Returns share_url. Nothing is emailed.
curl -X POST https://billing.kyberapps.com/api/v1/proposals/1/send \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'List invoices
Also returns stripe_connected and stripe_test_mode.
curl https://billing.kyberapps.com/api/v1/invoices?org_id=&status= -H "Authorization: Bearer $KB_TOKEN"
Create invoice from accepted proposal
With Stripe connected: creates a draft Stripe invoice from the proposal snapshot (send_invoice net-30 for PO, charge_automatically for card). send: true finalizes and sends it. Without Stripe, or for check/PO tracking, pass manual: true to create a local invoice record (amount defaults to the proposal total).
curl -X POST https://billing.kyberapps.com/api/v1/invoices \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"proposal_id": 1, "send": false}'Get invoice
curl https://billing.kyberapps.com/api/v1/invoices/1 -H "Authorization: Bearer $KB_TOKEN"
Finalize and send Stripe invoice
curl -X POST https://billing.kyberapps.com/api/v1/invoices/1/send \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'Mark paid (check or PO)
method: check, ach, po, other. reference: check number or remittance id.
curl -X POST https://billing.kyberapps.com/api/v1/invoices/1/mark-paid \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"method": "check", "reference": "chk 10422"}'List subscriptions
Annual plans mirrored from Stripe, per brand and per Stripe account. amount_cents is the annualised value; next_invoice_at is the renewal date.
curl https://billing.kyberapps.com/api/v1/subscriptions?org_id=&status=&brand=&account= -H "Authorization: Bearer $KB_TOKEN"
Create subscription from accepted proposal
The proposal's quote must have billing_mode=subscription (or pass it anyway to bill an accepted quote annually). Creates the Stripe subscription on the proposal's account (annual, N-year interval for multi-year lines), the first invoice follows Stripe's collection method. Nothing is emailed.
curl -X POST https://billing.kyberapps.com/api/v1/subscriptions \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"proposal_id": 1}'Get subscription
curl https://billing.kyberapps.com/api/v1/subscriptions/1 -H "Authorization: Bearer $KB_TOKEN"
Set subscription brand
brand: kyberapps, kybergate, kyberaccess, kyberwatch, kybercopy or unassigned.
curl -X PATCH https://billing.kyberapps.com/api/v1/subscriptions/1 \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"brand": "kybergate"}'Sync subscription from Stripe
curl -X POST https://billing.kyberapps.com/api/v1/subscriptions/1/sync \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'List payment links
curl https://billing.kyberapps.com/api/v1/payment-links?brand=&account=&org_id= -H "Authorization: Bearer $KB_TOKEN"
Create payment link
Stripe-hosted pay page. account (label) defaults to the brand's account. unit_cents or unit_price; qty; recurring: empty (one-off), month or year; product optional (KyberGate, KyberCopy, ...).
curl -X POST https://billing.kyberapps.com/api/v1/payment-links \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"brand": "kybergate", "description": "KyberGate \u00b7 1,200 devices \u00b7 2026-27", "unit_price": "6000", "qty": 1, "recurring": "", "org_id": 1}'Get payment link
curl https://billing.kyberapps.com/api/v1/payment-links/1 -H "Authorization: Bearer $KB_TOKEN"
Deactivate payment link
curl -X POST https://billing.kyberapps.com/api/v1/payment-links/1/deactivate \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'Customer portal session
Short-lived Stripe customer-portal URL for the org (invoice history, payment methods, billing details; cancel is off). account optional.
curl -X POST https://billing.kyberapps.com/api/v1/orgs/1/portal \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"account": "kyber-systems"}'List Stripe accounts
Label, Stripe account id, display name, default brand, mode, connected, webhook secret set, last sync. Never returns keys.
curl https://billing.kyberapps.com/api/v1/stripe-accounts -H "Authorization: Bearer $KB_TOKEN"
Sync one Stripe account
id is the label or numeric id. full: true also walks products and quotes (the Import existing action). Read-only against Stripe.
curl -X POST https://billing.kyberapps.com/api/v1/stripe-accounts/1/sync \
-H "Authorization: Bearer $KB_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"full": false}'Brands
The five brands (KyberApps umbrella + four products), the payee, and which Stripe account each brand bills from.
curl https://billing.kyberapps.com/api/v1/brands -H "Authorization: Bearer $KB_TOKEN"
Dashboard numbers
MRR, ARR, open, overdue, paid YTD, active subscriptions, pilots: total, per brand and per Stripe account.
curl https://billing.kyberapps.com/api/v1/dashboard?brand=&account= -H "Authorization: Bearer $KB_TOKEN"