Billing for Mosdos API (v1)
Billing for Mosdos keeps the accounts of mosdos and shuls: clients (parents or members), their children (sub-accounts), weekly charges, payments, statements, follow-ups and balance texts. This API lets the organisation's own assistant (an AI agent or a script) read and, with a "Read and edit" key, change that customer's own data, with the same rules as a person signed in to the app.
Basics
- Base URL:
https://billingformosdos.com/api/v1 - Authentication:
Authorization: Bearer <key>on every request. Keys are made by the organisation's admin in Settings › API access (Pro plan). A key is shown once. - Scope: a Read only key can only GET. A Read and edit key can also POST/PATCH. Writes with a read-only key answer 403.
- Which organisations: a key opens all organisations of its customer, or just one.
GET https://billingformosdos.com/api/v1/organisationslists them; every other call names one:https://billingformosdos.com/api/v1/orgs/{org_id}/.... Any other id answers 404. - JSON in and out. Every answer has
ok(true or false); errors haveerror(plain words you can show the user). - Money is in pence:
2500= £25.00. A client'sbalance_penceis negative when they owe (−2500 = owes £25.00) and positive when in credit;owes_penceis what they owe (0 if nothing). - Dates are
YYYY-MM-DD, UK time. - Limits: 60 calls a minute per key, 120 per customer; over that answers 429 with
Retry-After. - Idempotency: send
Idempotency-Key: <any unique text>on a POST; repeating the same request with the same key returns the first answer instead of doing it twice (kept 24 hours). - Every call is recorded. Changes appear in the organisation's change log (Activity › Recent activity) as "via API: <key name>".
- The key stops working when it is revoked or when the plan is no longer Pro (the answer says why).
Rules for assistants
- Only this customer's data. Use only IDs this API gave you.
- Before any change or send, tell the user exactly what you will do and wait for a clear yes.
- Never assume a payment. Record a payment only when the user says it came in.
- Texts and emails: preview first, show the user the preview, send only after a yes, with that preview's
confirm_token. - Never share the key.
How the billing works (so the numbers make sense)
- A client is a parent (or member, or donor). A client has children (sub-accounts). The client's balance is the sum of everything on all their children plus family-level lines.
- Weekly charges (auto-debits) are added automatically for the Sunday of each week, at each child's own weekly amount (
weekly_pence). Changing a child's weekly amount changes the charge from the next charge day; past charges stay. - The school year starts on 1 Elul, billed from the nearest Sunday (the organisation can override it).
- Statuses:
enrolled(normal),muted(no automatic charges or reminders; still enrolled),left_owing(left but still owes),history(left and settled). "Active" = enrolled + left_owing. - Payments are never assumed. Nothing is recorded unless a person confirms it. Card payments confirmed by Stripe are the only automatic ones.
- Texts (balance texts by SMS) go only from organisations that switched them on, only after a preview and a confirm, within the plan's monthly text allowance plus any credit. People with no mobile or "No texts" ticked are skipped.
- Emails (statements and balance reminders, Standard and Pro plans) go from the organisation's name with its own Reply-To, only from organisations that switched email on, only after a preview and a confirm. People with no email, "No emails" ticked, or an address that bounced are skipped; every email has an unsubscribe link.
Endpoints
About the key
GET https://billingformosdos.com/api/v1— this guide (text/markdown).GET https://billingformosdos.com/api/v1/openapi.json— the same, machine-readable (OpenAPI 3).GET https://billingformosdos.com/api/v1/me— the key's name, scope, customer, plan and organisations.GET https://billingformosdos.com/api/v1/organisations— the organisations this key opens:[{ id, name, org_type }].
Clients (parents / members)
GET https://billingformosdos.com/api/v1/orgs/{org}/clients?q=&status=— list.qsearches name, Hebrew name, reference, phone, email and children's names.status:active(default),muted,left_owing,history,all. Each:id, ref, name, name_he, title, first_name, surname, mobile, phone2, email, address, postcode, no_texts, status, children, weekly_pence, balance_pence, owes_pence, last_payment.GET https://billingformosdos.com/api/v1/orgs/{org}/clients/{id}— one client withchildrenand the last 50transactions.POST https://billingformosdos.com/api/v1/orgs/{org}/clients— add. Body:{ "name": "Moshe Cohen", "mobile": "07700 900123", "email": "", "address": "", "postcode": "", "no_texts": false, "no_emails": false }(nameorfirst_name+surnamerequired). Answers{ ok, id, ref }.PATCH https://billingformosdos.com/api/v1/orgs/{org}/clients/{id}— change any of:name, name_he, title, first_name, surname, mobile, phone2, email, address, postcode, note, no_texts, no_emails.POST https://billingformosdos.com/api/v1/orgs/{org}/clients/{id}/mute—{ "muted": true }pauses automatic charges and reminders from today;{ "muted": false }resumes (the muted weeks are not charged).GET https://billingformosdos.com/api/v1/orgs/{org}/clients/{id}/statement?from=YYYY-MM-DD&to=YYYY-MM-DD— the statement: opening balance, every line with a running balance, and the closing balance (pence).GET https://billingformosdos.com/api/v1/orgs/{org}/balances?min_owes_pence=1— every client who owes at least that much, largest first:{ id, name, owes_pence, balance_pence, last_payment }.
Children (sub-accounts)
GET https://billingformosdos.com/api/v1/orgs/{org}/children?client_id=— list (all, or one client's):id, client_id, name, name_he, grade, weekly_pence, muted, status, enrolled.POST https://billingformosdos.com/api/v1/orgs/{org}/children— add:{ "client_id": "...", "name": "Yossi", "grade": "Grade 1", "weekly_pence": 2500 }. The child's weekly amount is its weekly charge once the auto-debit is set up in the app.PATCH https://billingformosdos.com/api/v1/orgs/{org}/children/{id}— changename, name_he, grade, weekly_pence, note.POST https://billingformosdos.com/api/v1/orgs/{org}/children/{id}/mute—{ "muted": true }or{ "muted": false }.
Money
GET https://billingformosdos.com/api/v1/orgs/{org}/transactions?client_id=&from=&to=&kind=&limit=— newest first (max 500).kind:charge, auto_debit, payment, standing_order, pledge, correction, refund. Each:id, client_id, child_id, date, kind, direction(D= charge,C= payment/credit), amount_pence, description, method, paid_into.POST https://billingformosdos.com/api/v1/orgs/{org}/payments— record a payment the user confirmed:{ "client_id": "...", "amount_pence": 5000, "date": "2026-10-25", "method": "Bank transfer", "note": "", "paid_into": "", "child_id": "" }. Answers{ ok, id }. Only when the user says it came in.
Follow-ups
GET https://billingformosdos.com/api/v1/orgs/{org}/followups?status=open—open(default),doneorall:key, title, body, client_id, due, done, category.POST https://billingformosdos.com/api/v1/orgs/{org}/followups— add:{ "title": "Call about the balance", "client_id": "...", "due": "2026-11-01", "body": "" }.PATCH https://billingformosdos.com/api/v1/orgs/{org}/followups/{key}—{ "done": true }marks it done; alsotitle, body, due,add_note.
Settings (safe part)
GET https://billingformosdos.com/api/v1/orgs/{org}/settings— text settings and statement wording.PATCH https://billingformosdos.com/api/v1/orgs/{org}/settings— any of:texts_enabled, sender_name(UK sender ID, max 11 letters/digits), callback(call/text-back number), name_in_texts, text_wording(placeholders{org} {balance} {callback}), statement_title, statement_note, statement_footer_owing, statement_footer_paid, statement_footer_credit, bank_details. Plans, billing, users and keys can't be changed through the API.
Balance texts
POST https://billingformosdos.com/api/v1/orgs/{org}/texts/preview—{ "who": "owing" }(owing = balance due),"active","everyone", or{ "client_ids": [...] }. Answers who would get a text, who is skipped and why, an example, the number of texts, the estimated cost, this month's allowance, and aconfirm_token. Nothing is sent. (Read-and-edit keys.)POST https://billingformosdos.com/api/v1/orgs/{org}/texts/send—{ "confirm_token": "<from the preview>" }after the user said yes. Sends in batches: repeat the same call whileremaining> 0. Refused when texts are switched off, over the monthly allowance (402) or the preview is older than 2 hours. Opted-out clients and those without a mobile are never texted. On the test site and the demo it is always a dry run.GET https://billingformosdos.com/api/v1/orgs/{org}/texts/log— texts sent (numbers masked) with status.
Statements by email
POST https://billingformosdos.com/api/v1/orgs/{org}/emails/preview—{ "who": "owing" }(owing = balance due),"active","everyone", or{ "client_ids": [...] }; optional"lang": "en" | "he" | "yi","skip_zero": true,"from"/"to"(YYYY-MM-DD, the statement period). Answers who would get an email, who is skipped and why (no email, No emails ticked, bounced before, nothing owed), an example (subject and text), the platform's email allowance left today, and aconfirm_token. Sends nothing.POST https://billingformosdos.com/api/v1/orgs/{org}/emails/send—{ "confirm_token": "<from the preview>" }after the user said yes. Sends in batches: repeat the same call whileremaining> 0. Each client gets at most one email per preview, ever. From the API an email carries a link to the client's statement (valid 30 days) instead of a PDF. Refused when email isn't in the plan (403); a dry run when the organisation hasn't switched email on; 429 when the platform's daily or monthly email allowance is used up (send again later: nobody gets it twice).GET https://billingformosdos.com/api/v1/orgs/{org}/emails/log— emails sent (addresses masked) with status (sent, delivered, bounced, marked as spam, failed, dry run).
Change log
GET https://billingformosdos.com/api/v1/orgs/{org}/audit?limit=100— recent changes:at, user, action, summary(newest first).
Errors
- 400 something is missing or wrong (the
errorsays what), 401 no key / unknown key / revoked key, 403 not allowed (read-only key writing, or the plan isn't Pro), 404 not found (also: anything outside this customer), 402 over the text allowance, 409 a confirm is needed or the preview expired, 429 too many calls.
Example
curl -s https://billingformosdos.com/api/v1/organisations -H "Authorization: Bearer $KEY"
curl -s "https://billingformosdos.com/api/v1/orgs/ORG_ID/clients?q=cohen" -H "Authorization: Bearer $KEY"
curl -s -X POST https://billingformosdos.com/api/v1/orgs/ORG_ID/payments -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -H "Idempotency-Key: pay-123" -d '{"client_id":"CLIENT_ID","amount_pence":5000,"date":"2026-10-25","method":"Bank transfer"}'