API reference
Billing
The company's plan, billing details, invoices and paying them.
7 actions · base URL https://api.bizisy.com/v1 · generated from the same definitions as the API.
See billing#
POST/v1/platform/billing.getRead
Returns the organization's Bizisy plan: status (free_early_access before the start; free_first_month while the subscription's first, partial month is not charged, until starts_on; then active, past_due, needs_details, starting, paused or canceled; no card is needed: collection says whether invoices are charged to a card or emailed to pay), the active people count and billed quantity (at least 1), the unit price (€2.00 per active person per month, excluding VAT) and estimated monthly total, how VAT applies, the payment method summary (brand, last 4 digits, expiry; never the card number), the next charge date and the billing details, plus storage (500 MB included, then €1 per GB per month, i.e. €0.10 per 0.1 GB, on the month's highest size), optional emails (10 per active person per month included, pooled, then €1 per 1,000, i.e. €0.10 per block of 100) and the total so far. open_invoices lists the unpaid invoices (overdue ones flagged, overdue totals them) and pause says since when the company is paused and when it is closed if still unpaid. Billed monthly in arrears at the end of each calendar month for the people active then and the storage peak; the month billing starts in is not charged. Owners and admins only.
- Who can call it
- Manage key owner admin
- MCP tool
platform_billing_geton HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
No input: send {}.
Returns
27 fields
mode"test" | "live"requiredtest: Stripe sandbox, nothing is really charged.
statusstring (enum)requiredpaused: an invoice is unpaid past its due date (or billing details are missing past their deadline): only owners and admins can sign in, to pay, save a card or export data; everything else is refused until it is paid. needs_details: billing has started and billing details are missing (no card is needed).
One of:
free_early_access,free_first_month,starting,needs_details,active,past_due,paused,canceled.starts_onstring | nullrequiredWhen this organization starts paying (YYYY-MM-DD, always a 1st): the 1st of the month after its start date (the announced date, never earlier than 30 days after its notice email), since the month billing starts in is not charged; null while no date is announced.
active_peopleintegerrequiredPeople active today (pre-hires and leavers are not counted).
quantityintegerrequiredPeople billed: the active count, at least 1.
unit_price_centsintegerrequiredcurrency"EUR"requiredestimated_monthly_centsintegerrequiredquantity × unit price, excluding VAT. Billed monthly in arrears at the end of each calendar month for the people active then.
vat"portuguese_vat" | "reverse_charge" | "export"requiredHow VAT applies (from the billing details); null without details.
payment_methodobject | nullrequired4 fields
brandstringrequiredlast4stringrequiredexp_monthintegerrequiredexp_yearintegerrequired
next_charge_onstring | nullrequiredThe next charge (a 1st: the end of the month being billed); during the uncharged first month, the end of the first paid month.
cancel_atstring | nullrequiredSet when the subscription was canceled: it ends (and access stays) until this date.
detailsobject | nullrequired5 fields
legal_namestringrequiredvat_numberstring | nullrequiredemailstringrequiredaddressobjectrequired5 fields
line1stringrequired1–200 characters.
line2string | nullrequiredUp to 200 characters.
citystringrequired1–100 characters.
postal_codestringrequired1–20 characters.
countrystringrequiredPattern
^[A-Z]{2}$.
vat_verification"valid" | "invalid" | "unverified_network" | "unverified_error" | "not_applicable"requiredEU VAT numbers outside Portugal are checked with the EU VIES service when saved: invalid means Portuguese VAT applies; unverified_network (VIES unreachable) and unverified_error (VIES refused the check; Bizisy is alerted) keep the format check until VIES answers. null on a dry run: the preview uses the format check and VIES is asked only when the change is saved.
billing_starts_onstring | nullrequiredWhen billing starts for this organization (YYYY-MM-DD, Lisbon): from this day a payment method is needed; the month it falls in is not charged. null while no date is announced.
first_charge_onstring | nullrequiredWhen the payment method is first charged (YYYY-MM-DD, a 1st), while nothing has been charged yet: the end of the first paid month, since billing is monthly in arrears and the month billing starts in is not charged. null without an announced start date, once charging has begun, when the subscription is set to cancel, and for an organization subscribed before (a new subscription is then charged from its first month).
defaultsobjectrequiredSuggestions for an empty details form: the legal entity (or the company) and the caller's email.
5 fields
legal_namestringrequiredemailstringrequiredcountrystringrequiredvat_numberstring | nullrequiredThe legal entity's tax id, when it has one.
source"legal_entity" | "organization"requiredlegal_entity: name, country and tax id come from the company's first legal entity; organization: from the company name and country.
can_checkoutbooleanrequiredA card can be saved through Stripe Checkout (no card saved yet, or no running subscription; once a card pays, it changes in the portal). Saving one makes later invoices charged automatically.
collection"card" | "invoice"requiredHow invoices are paid: card (charged automatically) or invoice (emailed at month end, paid within 14 days on Stripe's page by card, SEPA Direct Debit or bank transfer); null before a subscription exists.
open_invoiceobject | nullrequiredThe oldest unpaid invoice, if any.
8 fields
idstringrequirednumberstring | nullrequiredamount_due_centsintegerrequiredWhat is left to pay, VAT included.
issued_onstringrequiredYYYY-MM-DD (Lisbon) the invoice was issued.
due_onstringrequiredYYYY-MM-DD (Lisbon): if it is unpaid then, Bizisy pauses for everyone except owners and admins.
days_leftintegerrequiredWhole days until due_on (0 = due today or past).
collection"card" | "invoice"requiredcard: a card payment that failed; invoice: emailed, paid on Stripe's page.
overduebooleanrequiredUnpaid past the end of its due day (Lisbon): it counts toward the pause; paying every overdue invoice unpauses.
open_invoicesobject[]requiredEvery unpaid invoice, oldest first (at most 12). Billing continues while paused, so there may be several.
8 fields
idstringrequirednumberstring | nullrequiredamount_due_centsintegerrequiredWhat is left to pay, VAT included.
issued_onstringrequiredYYYY-MM-DD (Lisbon) the invoice was issued.
due_onstringrequiredYYYY-MM-DD (Lisbon): if it is unpaid then, Bizisy pauses for everyone except owners and admins.
days_leftintegerrequiredWhole days until due_on (0 = due today or past).
collection"card" | "invoice"requiredcard: a card payment that failed; invoice: emailed, paid on Stripe's page.
overduebooleanrequiredUnpaid past the end of its due day (Lisbon): it counts toward the pause; paying every overdue invoice unpauses.
overdueobject | nullrequiredUnpaid invoices past the end of their due day: every one must be paid to lift a pause (or reopen a company closed for non-payment).
2 fields
countintegerrequiredtotal_centsintegerrequired
pauseobject | nullrequiredSet while the company is paused (pay-or-lock).
3 fields
reason"unpaid" | "details_missing"requiredsincestringrequiredYYYY-MM-DD (Lisbon).
closes_onstringrequiredYYYY-MM-DD: if still unpaid then, the company account is closed (deleted 14 days later unless paid).
details_due_onstring | nullrequiredneeds_details: YYYY-MM-DD when Bizisy pauses if billing details are still missing.
can_open_portalbooleanrequiredThe Stripe customer portal exists (after the first checkout).
storageobject | nullrequiredStorage above 500 MB (documents); null where the server has no file storage.
7 fields
bytesintegerrequiredStored now (documents, photos, logo).
peak_bytesintegerrequiredThis month's highest size: what storage is billed on.
free_bytesintegerrequiredIncluded: 500 MB.
unit_bytesintegerrequiredOne unit: 0.1 GB.
billable_unitsintegerrequiredunit_price_centsintegerrequired€0.10 per unit per month, excluding VAT (€1 per GB).
estimated_centsintegerrequiredThis month's storage so far, excluding VAT; billed with the people at month end.
emailobjectrequiredOptional emails above the allowance (Settings → Notifications).
8 fields
sentintegerrequiredOptional emails sent this month (reminders and task digests, approval requests, document notices; a digest is one).
allowanceintegerrequiredIncluded this month: 10 per person billed, pooled.
billable_unitsintegerrequiredBlocks of 100 emails above the allowance, rounded up.
unit_sizeintegerrequiredunit_price_centsintegerrequired€0.10 per block of 100, excluding VAT (= €1 per 1,000).
estimated_centsintegerrequiredThis month's optional emails above the allowance so far, excluding VAT (counted even when not billed).
billedbooleanrequiredThese are charged this month (a paid subscription with the email price, on or after billing_from); false: included, and left out of estimated_total_cents.
billing_fromstring | nullrequiredYYYY-MM-DD (a 1st): from when they are charged, at least 30 days after the owners and admins were told the price; null until they were told.
estimated_total_centsintegerrequiredPeople, storage and optional emails so far this month, excluding VAT.
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.get \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.get', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.get",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"mode": "test",
"status": "active",
"starts_on": "2026-12-01",
"active_people": 7,
"quantity": 7,
"unit_price_cents": 200,
"currency": "EUR",
"estimated_monthly_cents": 1400,
"vat": "portuguese_vat",
"payment_method": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2030
},
"next_charge_on": "2027-01-01",
"cancel_at": null,
"details": {
"legal_name": "Acme, Lda",
"vat_number": "PT501442600",
"email": "billing@acme.test",
"address": {
"line1": "Rua Augusta 100",
"line2": null,
"city": "Lisboa",
"postal_code": "1100-053",
"country": "PT"
},
"vat_verification": "not_applicable"
},
"billing_starts_on": "2026-11-04",
"first_charge_on": null,
"defaults": {
"legal_name": "Acme Lda",
"email": "ana@acme.test",
"country": "PT",
"vat_number": "501442600",
"source": "legal_entity"
},
"can_checkout": false,
"can_open_portal": true,
"storage": {
"bytes": 780000000,
"peak_bytes": 820000000,
"free_bytes": 500000000,
"unit_bytes": 100000000,
"billable_units": 4,
"unit_price_cents": 10,
"estimated_cents": 40
},
"email": {
"sent": 182,
"allowance": 70,
"billable_units": 2,
"unit_size": 100,
"unit_price_cents": 10,
"estimated_cents": 20,
"billed": true,
"billing_from": "2026-12-01"
},
"estimated_total_cents": 1460,
"collection": "card",
"open_invoice": null,
"open_invoices": [],
"overdue": null,
"pause": null,
"details_due_on": null
}
}Change billing details#
POST/v1/platform/billing.update_detailsWrite
Sets the billing details printed on invoices: legal_name, vat_number (NIF in Portugal, required and checked: companies and sole traders; EU VAT numbers get their country prefix and a format check), email (where invoices go) and address { line1, line2?, city, postal_code, country }. Send the whole set every time. The country and VAT number decide VAT: Portugal (and EU without a VAT number) pays Portuguese VAT, EU businesses with a VAT number are reverse charged, outside the EU is exempt. Owners and admins only; preview with dry_run.
- Who can call it
- Manage key owner admin
- MCP tool
platform_billing_update_detailson HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
legal_namestringrequiredThe legal name on invoices, e.g. "Acme, Lda".
2–200 characters.
vat_numberstring | nullNIF / VAT number. Required in Portugal (a valid NIF of a company or sole trader: first digit 1, 2, 3, 5, 6, 8 or 9; 999999990 refused); EU numbers get their country prefix; optional outside Portugal.
Up to 40 characters.
emailemailrequiredWhere invoices and billing emails go.
Up to 254 characters.
addressobjectrequired5 fields
line1stringrequired1–200 characters.
line2string | nullUp to 200 characters.
citystringrequired1–100 characters.
postal_codestringrequired1–20 characters.
countryanyrequiredISO 3166 two-letter code, e.g. PT.
Returns
27 fields
mode"test" | "live"requiredtest: Stripe sandbox, nothing is really charged.
statusstring (enum)requiredpaused: an invoice is unpaid past its due date (or billing details are missing past their deadline): only owners and admins can sign in, to pay, save a card or export data; everything else is refused until it is paid. needs_details: billing has started and billing details are missing (no card is needed).
One of:
free_early_access,free_first_month,starting,needs_details,active,past_due,paused,canceled.starts_onstring | nullrequiredWhen this organization starts paying (YYYY-MM-DD, always a 1st): the 1st of the month after its start date (the announced date, never earlier than 30 days after its notice email), since the month billing starts in is not charged; null while no date is announced.
active_peopleintegerrequiredPeople active today (pre-hires and leavers are not counted).
quantityintegerrequiredPeople billed: the active count, at least 1.
unit_price_centsintegerrequiredcurrency"EUR"requiredestimated_monthly_centsintegerrequiredquantity × unit price, excluding VAT. Billed monthly in arrears at the end of each calendar month for the people active then.
vat"portuguese_vat" | "reverse_charge" | "export"requiredHow VAT applies (from the billing details); null without details.
payment_methodobject | nullrequired4 fields
brandstringrequiredlast4stringrequiredexp_monthintegerrequiredexp_yearintegerrequired
next_charge_onstring | nullrequiredThe next charge (a 1st: the end of the month being billed); during the uncharged first month, the end of the first paid month.
cancel_atstring | nullrequiredSet when the subscription was canceled: it ends (and access stays) until this date.
detailsobject | nullrequired5 fields
legal_namestringrequiredvat_numberstring | nullrequiredemailstringrequiredaddressobjectrequired5 fields
line1stringrequired1–200 characters.
line2string | nullrequiredUp to 200 characters.
citystringrequired1–100 characters.
postal_codestringrequired1–20 characters.
countrystringrequiredPattern
^[A-Z]{2}$.
vat_verification"valid" | "invalid" | "unverified_network" | "unverified_error" | "not_applicable"requiredEU VAT numbers outside Portugal are checked with the EU VIES service when saved: invalid means Portuguese VAT applies; unverified_network (VIES unreachable) and unverified_error (VIES refused the check; Bizisy is alerted) keep the format check until VIES answers. null on a dry run: the preview uses the format check and VIES is asked only when the change is saved.
billing_starts_onstring | nullrequiredWhen billing starts for this organization (YYYY-MM-DD, Lisbon): from this day a payment method is needed; the month it falls in is not charged. null while no date is announced.
first_charge_onstring | nullrequiredWhen the payment method is first charged (YYYY-MM-DD, a 1st), while nothing has been charged yet: the end of the first paid month, since billing is monthly in arrears and the month billing starts in is not charged. null without an announced start date, once charging has begun, when the subscription is set to cancel, and for an organization subscribed before (a new subscription is then charged from its first month).
defaultsobjectrequiredSuggestions for an empty details form: the legal entity (or the company) and the caller's email.
5 fields
legal_namestringrequiredemailstringrequiredcountrystringrequiredvat_numberstring | nullrequiredThe legal entity's tax id, when it has one.
source"legal_entity" | "organization"requiredlegal_entity: name, country and tax id come from the company's first legal entity; organization: from the company name and country.
can_checkoutbooleanrequiredA card can be saved through Stripe Checkout (no card saved yet, or no running subscription; once a card pays, it changes in the portal). Saving one makes later invoices charged automatically.
collection"card" | "invoice"requiredHow invoices are paid: card (charged automatically) or invoice (emailed at month end, paid within 14 days on Stripe's page by card, SEPA Direct Debit or bank transfer); null before a subscription exists.
open_invoiceobject | nullrequiredThe oldest unpaid invoice, if any.
8 fields
idstringrequirednumberstring | nullrequiredamount_due_centsintegerrequiredWhat is left to pay, VAT included.
issued_onstringrequiredYYYY-MM-DD (Lisbon) the invoice was issued.
due_onstringrequiredYYYY-MM-DD (Lisbon): if it is unpaid then, Bizisy pauses for everyone except owners and admins.
days_leftintegerrequiredWhole days until due_on (0 = due today or past).
collection"card" | "invoice"requiredcard: a card payment that failed; invoice: emailed, paid on Stripe's page.
overduebooleanrequiredUnpaid past the end of its due day (Lisbon): it counts toward the pause; paying every overdue invoice unpauses.
open_invoicesobject[]requiredEvery unpaid invoice, oldest first (at most 12). Billing continues while paused, so there may be several.
8 fields
idstringrequirednumberstring | nullrequiredamount_due_centsintegerrequiredWhat is left to pay, VAT included.
issued_onstringrequiredYYYY-MM-DD (Lisbon) the invoice was issued.
due_onstringrequiredYYYY-MM-DD (Lisbon): if it is unpaid then, Bizisy pauses for everyone except owners and admins.
days_leftintegerrequiredWhole days until due_on (0 = due today or past).
collection"card" | "invoice"requiredcard: a card payment that failed; invoice: emailed, paid on Stripe's page.
overduebooleanrequiredUnpaid past the end of its due day (Lisbon): it counts toward the pause; paying every overdue invoice unpauses.
overdueobject | nullrequiredUnpaid invoices past the end of their due day: every one must be paid to lift a pause (or reopen a company closed for non-payment).
2 fields
countintegerrequiredtotal_centsintegerrequired
pauseobject | nullrequiredSet while the company is paused (pay-or-lock).
3 fields
reason"unpaid" | "details_missing"requiredsincestringrequiredYYYY-MM-DD (Lisbon).
closes_onstringrequiredYYYY-MM-DD: if still unpaid then, the company account is closed (deleted 14 days later unless paid).
details_due_onstring | nullrequiredneeds_details: YYYY-MM-DD when Bizisy pauses if billing details are still missing.
can_open_portalbooleanrequiredThe Stripe customer portal exists (after the first checkout).
storageobject | nullrequiredStorage above 500 MB (documents); null where the server has no file storage.
7 fields
bytesintegerrequiredStored now (documents, photos, logo).
peak_bytesintegerrequiredThis month's highest size: what storage is billed on.
free_bytesintegerrequiredIncluded: 500 MB.
unit_bytesintegerrequiredOne unit: 0.1 GB.
billable_unitsintegerrequiredunit_price_centsintegerrequired€0.10 per unit per month, excluding VAT (€1 per GB).
estimated_centsintegerrequiredThis month's storage so far, excluding VAT; billed with the people at month end.
emailobjectrequiredOptional emails above the allowance (Settings → Notifications).
8 fields
sentintegerrequiredOptional emails sent this month (reminders and task digests, approval requests, document notices; a digest is one).
allowanceintegerrequiredIncluded this month: 10 per person billed, pooled.
billable_unitsintegerrequiredBlocks of 100 emails above the allowance, rounded up.
unit_sizeintegerrequiredunit_price_centsintegerrequired€0.10 per block of 100, excluding VAT (= €1 per 1,000).
estimated_centsintegerrequiredThis month's optional emails above the allowance so far, excluding VAT (counted even when not billed).
billedbooleanrequiredThese are charged this month (a paid subscription with the email price, on or after billing_from); false: included, and left out of estimated_total_cents.
billing_fromstring | nullrequiredYYYY-MM-DD (a 1st): from when they are charged, at least 30 days after the owners and admins were told the price; null until they were told.
estimated_total_centsintegerrequiredPeople, storage and optional emails so far this month, excluding VAT.
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.update_details \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"legal_name": "Acme, Lda",
"vat_number": "501442600",
"email": "billing@acme.test",
"address": {
"line1": "Rua Augusta 100",
"city": "Lisboa",
"postal_code": "1100-053",
"country": "PT"
}
}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.update_details', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"legal_name": "Acme, Lda",
"vat_number": "501442600",
"email": "billing@acme.test",
"address": {
"line1": "Rua Augusta 100",
"city": "Lisboa",
"postal_code": "1100-053",
"country": "PT"
}
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.update_details",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"legal_name": "Acme, Lda",
"vat_number": "501442600",
"email": "billing@acme.test",
"address": {
"line1": "Rua Augusta 100",
"city": "Lisboa",
"postal_code": "1100-053",
"country": "PT",
},
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"mode": "test",
"status": "active",
"starts_on": "2026-12-01",
"active_people": 7,
"quantity": 7,
"unit_price_cents": 200,
"currency": "EUR",
"estimated_monthly_cents": 1400,
"vat": "portuguese_vat",
"payment_method": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2030
},
"next_charge_on": "2027-01-01",
"cancel_at": null,
"details": {
"legal_name": "Acme, Lda",
"vat_number": "PT501442600",
"email": "billing@acme.test",
"address": {
"line1": "Rua Augusta 100",
"line2": null,
"city": "Lisboa",
"postal_code": "1100-053",
"country": "PT"
},
"vat_verification": "not_applicable"
},
"billing_starts_on": "2026-11-04",
"first_charge_on": null,
"defaults": {
"legal_name": "Acme Lda",
"email": "ana@acme.test",
"country": "PT",
"vat_number": "501442600",
"source": "legal_entity"
},
"can_checkout": false,
"can_open_portal": true,
"storage": {
"bytes": 780000000,
"peak_bytes": 820000000,
"free_bytes": 500000000,
"unit_bytes": 100000000,
"billable_units": 4,
"unit_price_cents": 10,
"estimated_cents": 40
},
"email": {
"sent": 182,
"allowance": 70,
"billable_units": 2,
"unit_size": 100,
"unit_price_cents": 10,
"estimated_cents": 20,
"billed": true,
"billing_from": "2026-12-01"
},
"estimated_total_cents": 1460,
"collection": "card",
"open_invoice": null,
"open_invoices": [],
"overdue": null,
"pause": null,
"details_due_on": null
}
}Add a payment method#
POST/v1/platform/billing.checkoutWrite
Web app only: starts a Stripe Checkout page that saves a payment method and returns its short-lived url. Nothing is charged on that page: from the start date, Bizisy subscribes the organization itself and charges the saved method monthly in arrears at the end of each calendar month (€2 per active person, excluding VAT, plus VAT where it applies); the month the subscription starts in is not charged. Needs billing details first; once the subscription runs, the card changes in the billing portal. Refused for API keys and AI assistants: tell the user to open Settings → Billing in Bizisy. Owners and admins only.
- Web app only
- Refused for API keys and connected apps. Payment pages open in the browser, for owners and admins signed in to Bizisy.
- MCP tool
platform_billing_checkouton HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
No input: send {}.
Returns
urlstring | nullrequiredNull on a dry run.
mode"setup"required
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.checkout \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.checkout', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.checkout",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"url": "https://checkout.stripe.com/c/pay/cs_test_1",
"mode": "setup"
}
}Open the billing portal#
POST/v1/platform/billing.portalWrite
Web app only: returns a short-lived url to Stripe's customer portal, where the user changes the payment method, downloads Stripe receipts or cancels (at the end of the period already paid). Refused for API keys and AI assistants: tell the user to open Settings → Billing in Bizisy. Owners and admins only; needs a first checkout.
- Web app only
- Refused for API keys and connected apps. Payment pages open in the browser, for owners and admins signed in to Bizisy.
- MCP tool
platform_billing_portalon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
No input: send {}.
Returns
urlstring | nullrequiredNull on a dry run.
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.portal \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.portal', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.portal",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"url": "https://billing.stripe.com/p/session/test_1"
}
}List invoices#
POST/v1/platform/billing.invoices.listRead
Lists the organization's Bizisy invoices with an amount to pay, newest first (at most 100; €0 invoices such as the uncharged first month are left out): date, period, people billed, total with and without VAT, payment status (paid, open, failed), the certified invoice (fatura) number and status, and Stripe's receipt page. Owners and admins only.
- Who can call it
- Manage key owner admin
- MCP tool
platform_billing_invoices_liston HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
No input: send {}.
Returns
An array of objects with 12 fields
An array of objects:
idstringrequirednumberstring | nullrequireddatestringrequiredperiod_startstring | nullrequiredperiod_endstring | nullrequiredquantityintegerrequiredtotal_centsintegerrequiredtotal_excluding_vat_centsintegerrequiredcurrencystringrequiredstatus"paid" | "open" | "failed" | "void" | "uncollectible"requiredfaturaobjectrequired2 fields
status"pending" | "issued" | "failed" | "test"requiredThe certified invoice (fatura): pending = being issued (retrying); issued = final; failed = delayed, Bizisy issues it by hand; test = test mode, no fatura is issued.
numberstring | nullrequired
receipt_urlstring | nullrequiredStripe's payment receipt page.
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.invoices.list \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.invoices.list', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.invoices.list",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": [
{
"id": "in_1",
"number": "BZ-0001",
"date": "2026-12-01",
"period_start": "2026-12-01",
"period_end": "2027-01-01",
"quantity": 7,
"total_cents": 1722,
"total_excluding_vat_cents": 1400,
"currency": "EUR",
"status": "paid",
"fatura": {
"status": "issued",
"number": "FR 2026/12"
},
"receipt_url": "https://invoice.stripe.com/i/acct_1/test_1"
}
]
}Download a certified invoice#
POST/v1/platform/billing.invoices.pdfRead
Web app only: returns a download link to the certified invoice (fatura) PDF of one paid invoice (invoice_id from platform_billing_invoices_list), valid for a few seconds. Only for issued faturas. Refused for API keys and AI assistants. Owners and admins only.
- Web app only
- Refused for API keys and connected apps. Invoices download in the browser, for owners and admins signed in to Bizisy.
- MCP tool
platform_billing_invoices_pdfon HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
invoice_idstringrequired1–100 characters.
Returns
urlstringrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.invoices.pdf \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"invoice_id":"in_1"}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.invoices.pdf', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"invoice_id": "in_1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.invoices.pdf",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"invoice_id": "in_1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"url": "https://mediaapi.moloni.org/x.pdf?jwt=t"
}
}Pay an open invoice#
POST/v1/platform/billing.payRead
Web app only: returns Stripe's payment page for the oldest unpaid Bizisy invoice (or invoice_id from platform_billing_get open_invoice), fetched now and never stored. On that page an owner or admin pays by card, SEPA Direct Debit or bank transfer; paying a paused company's overdue invoice unpauses it at once. Refused for API keys and AI assistants: tell the user to open Settings → Billing in Bizisy and choose Pay now. Owners and admins only.
- Web app only
- Refused for API keys and connected apps. Invoices are paid on Stripe's page in the browser, by owners and admins signed in to Bizisy.
- MCP tool
platform_billing_payon HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
invoice_idstring1–100 characters.
Returns
urlstringrequiredinvoiceobjectrequired8 fields
idstringrequirednumberstring | nullrequiredamount_due_centsintegerrequiredWhat is left to pay, VAT included.
issued_onstringrequiredYYYY-MM-DD (Lisbon) the invoice was issued.
due_onstringrequiredYYYY-MM-DD (Lisbon): if it is unpaid then, Bizisy pauses for everyone except owners and admins.
days_leftintegerrequiredWhole days until due_on (0 = due today or past).
collection"card" | "invoice"requiredcard: a card payment that failed; invoice: emailed, paid on Stripe's page.
overduebooleanrequiredUnpaid past the end of its due day (Lisbon): it counts toward the pause; paying every overdue invoice unpauses.
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/platform/billing.pay \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"invoice_id":"in_2"}'const res = await fetch('https://api.bizisy.com/v1/platform/billing.pay', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"invoice_id": "in_2"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/platform/billing.pay",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"invoice_id": "in_2",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"url": "https://invoice.stripe.com/i/acct_1/test_1",
"invoice": {
"id": "in_2",
"number": "BZ-0002",
"amount_due_cents": 1968,
"issued_on": "2027-01-01",
"due_on": "2027-01-15",
"days_left": 6,
"collection": "invoice",
"overdue": false
}
}
}Something missing or wrong on this page? Write to hello@bizisy.com.