Stable Pro API · v1
Endpoints and objects
Every endpoint with its permission, parameters and response, and every object with its fields. Generated from the OpenAPI contract.
Field names, codes and values are the contract: they are the same in every language.
Endpoints
/api/v1/connectionThe connection of the calling key: name, permissions, and the key itself (never the secret)
- Permission
- any valid key
- Parameters
- lang
- Response
- Connection
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/codesThe dictionary of every code the API returns, with names in the requested language (?lang=, Accept-Language)
- Permission
- any valid key
- Parameters
- lang
- Response
- Codes
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/organizationThe stable of the calling key: name, country, currency, time zone, language, whether Stable Pro calculates taxes
- Permission
- any valid key
- Parameters
- lang
- Response
- Organization
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/customersEveryone with at least one charge, paid or not, member or staff; with customers.fiscal:read also the invoice details
- Permission
- customers:read
- Parameters
- langlimitstarting_after
- Response
- CustomerList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/customers/{id}One customer; with customers.fiscal:read also the invoice details. Not of this stable: 404
- Permission
- customers:read
- Parameters
- id (path)lang
- Response
- Customer
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/customers/{id}/balanceWhat the customer owes today, what comes later, and the credit they can spend
- Permission
- charges:read
- Parameters
- id (path)lang
- Response
- Balance
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/chargesEvery charge to the customers, paid or not (never the staff pay)
- Permission
- charges:read
- Parameters
- langlimitstarting_after
- Filters
- customer — Only this customer (its id)
- accounting_month — Only this accounting month (YYYY-MM): the month the fact counts in, see Conventions
- Response
- ChargeList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/charges/{id}One charge, as it is now: amount and taxes are birth plus adjustments plus tax changes
- Permission
- charges:read
- Parameters
- id (path)lang
- Response
- Charge
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/adjustmentsAdjustments of charges
- Permission
- charges:read
- Parameters
- langlimitstarting_after
- Filters
- charge — Only the adjustments of this charge (its id)
- accounting_month — Only this accounting month (YYYY-MM): the month the fact counts in, see Conventions
- Response
- AdjustmentList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/adjustments/{id}One adjustment: action, reason, category, signed amount, consideration_effect, the tax difference
- Permission
- charges:read
- Parameters
- id (path)lang
- Response
- Adjustment
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/paymentsMoney movements of the customers (payments, refunds, reversals, credit used)
- Permission
- payments:read
- Parameters
- langlimitstarting_after
- Filters
- customer — Only this customer (its id)
- Response
- PaymentList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/payments/{id}One money movement, with its allocations; who paid on behalf of the customer
- Permission
- payments:read
- Parameters
- id (path)lang
- Response
- Payment
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/allocations/{id}How much of a movement goes to a charge, signed
- Permission
- payments:read
- Parameters
- id (path)lang
- Response
- Allocation
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/credit-entriesMovements of the customers' credit (born, grown, used, refunded)
- Permission
- payments:read
- Parameters
- langlimitstarting_after
- Filters
- customer — Only this customer (its id)
- Response
- CreditEntryList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/credit-entries/{id}One movement of a customer's credit
- Permission
- payments:read
- Parameters
- id (path)lang
- Response
- CreditEntry
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/receiptsReceipts of Stable Pro (R: payment receipts, RB: refund confirmations), in order of issue; never fiscal documents
- Permission
- receipts:read
- Parameters
- langlimitstarting_after
- Filters
- customer — Only this customer (its id)
- payment — Only the receipts of this money movement (its id)
- Response
- ReceiptList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/receipts/{id}One receipt: kind, the number as printed, status, the payment it confirms, the frozen amount
- Permission
- receipts:read
- Parameters
- id (path)lang
- Response
- Receipt
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/receipts/{id}/pdfThe PDF of the receipt, the same the customer got. When it carries the tax data of who paid on behalf of the customer, it also needs customers.fiscal:read (else 403)
- Permission
- receipts:read
- Parameters
- id (path)lang
- Response
- application/pdf
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/eventsWhat happened, in order: read after your cursor to stay in sync. Each event needs the permission of the object it points to. While the stable's history is being loaded: 503 events-not-ready
- Permission
- any valid key
- Parameters
- langlimitafter
- Response
- EventList
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
/api/v1/events/{id}One event. Of another stable, or of a kind your key does not read: 404
- Permission
- any valid key
- Parameters
- id (path)lang
- Response
- Event
- Errors
- 400 · 401 · 403 · 404 · 429 · 500 · 503
Objects
Problem
| Field | Type | Description |
|---|---|---|
| type | string (uri) | Stable, in English: decide on this, not on the text |
| title | string | In English |
| status | integer | |
| detail | string · optional | A sentence for people, in the requested language (?lang=, Accept-Language) |
| reason | string · optional missing · malformed · wrong_environment · unknown · connection_revoked · revoked · expired · rotated | 401 only: why the key is not valid |
| missing_permission | string · optional charges:read · payments:read · receipts:read · customers:read · customers.fiscal:read · external-documents:write | 403 forbidden only |
| invalid_param | string · optional | 400 only: the parameter that is not valid |
Connection
| Field | Type | Description |
|---|---|---|
| object | "connection" | |
| id | string (uuid) | |
| name | string | |
| permissions | array of string | |
| created_at | string (date-time) | RFC 3339, UTC |
| key | object | |
| key.id | string (uuid) | |
| key.last_four | string | |
| key.environment | string live · test | live = production (sp_live_), test = staging (sp_test_) |
| key.created_at | string (date-time) | RFC 3339, UTC |
| key.expires_at | string (date-time) · nullable | RFC 3339, UTC |
| key.retires_at | string (date-time) · nullable | After a rotation: when this key stops working |
Organization
| Field | Type | Description |
|---|---|---|
| object | "organization" | |
| id | string (uuid) | |
| name | string | |
| legal_name | string · nullable | |
| country | string · nullable | ISO 3166-1 alpha-2 |
| currency | string | ISO 4217 |
| timezone | string | IANA |
| language | string | The stable's language: Stable Pro does not know each customer's |
| locale | string | BCP 47, for formatting |
| taxes | object | |
| taxes.calculated_by | string stable_pro · external | external = Stable Pro does not calculate taxes this month: nothing more |
| taxes.amount_basis | "gross" | Every amount is the total the customer pays |
| receipts_shown_to_customers | boolean | false: the stable chose not to give Stable Pro receipts to its customers while software is connected; they still exist and are numbered (GET /receipts) |
Customer
| Field | Type | Description |
|---|---|---|
| object | "customer" | |
| id | string (uuid) | The customer code: it never changes |
| kind | string member · staff | |
| name | string | |
| given_name | string · nullable | |
| family_name | string · nullable | |
| active | boolean | false: left the stable, or removed; their charges are still invoiceable |
| created_at | string (date-time) | RFC 3339, UTC |
| billing_address | object · nullable · optional | customers.fiscal:read only |
| billing_address.line1 | string · nullable | |
| billing_address.line2 | string · nullable | |
| billing_address.postal_code | string · nullable | |
| billing_address.city | string · nullable | |
| billing_address.subdivision | string · nullable | ISO 3166-2 (IT-MI, US-OH) |
| billing_address.country | string · nullable | ISO 3166-1 alpha-2 |
| billing_address_text | string · nullable · optional | customers.fiscal:read only: the old free-text address, only while billing_address is empty |
| tax_identifiers | array of object · optional | customers.fiscal:read only |
| tax_identifiers[].scheme | string | VAT, or an ISO 6523 ICD (0210 Italian fiscal code, 0211 Italian VAT number) |
| tax_identifiers[].value | string | |
| tax_code | string · nullable · optional | customers.fiscal:read only: the old fiscal code, without a scheme |
CustomerList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Customer | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
Balance
| Field | Type | Description |
|---|---|---|
| object | "balance" | |
| customer_id | string (uuid) | |
| currency | string | |
| amount_due | integer | What is due today: charges already visible |
| amount_scheduled | integer | Charges that become visible later |
| credit | integer | Credit that can be spent on a charge |
| as_of | string (date) | Today, in the stable's time zone |
Charge
| Field | Type | Description |
|---|---|---|
| object | "charge" | |
| id | string (uuid) | |
| customer_id | string (uuid) | |
| type | string | Open list: boarding, service_charge, lesson_drop_in, lesson_plan, health_record, … |
| description | string | As the stable wrote it |
| period_start | string (date) | YYYY-MM-DD |
| period_end | string (date) | YYYY-MM-DD |
| competence_month | string | YYYY-MM |
| accounting_month | string | The later of competence and registration month: computed by Stable Pro |
| due_date | string (date) | YYYY-MM-DD |
| visible_from | string (date) | YYYY-MM-DD |
| quantity | "1" | |
| unit | string MON · ANN · C62 | UNECE Rec. 20 |
| unit_amount | integer | Minor units of the currency (ISO 4217) |
| currency | string | |
| original_amount | integer | At birth |
| amount | integer | Now: birth plus adjustments |
| amount_paid | integer | Minor units of the currency (ISO 4217) |
| amount_remaining | integer | Minor units of the currency (ISO 4217) |
| amount_basis | "gross" | |
| tax_calculated_by | string stable_pro · external | |
| tax_treatment | string standard_rated · zero_rated · not_calculated · undetermined | |
| taxable_amount | integer | Minor units of the currency (ISO 4217) |
| taxes | array of object | |
| taxes[].type | "vat" | Open list: other types may come |
| taxes[].jurisdiction | string · nullable | ISO 3166-1 alpha-2 of the stable |
| taxes[].category | string · nullable | UNCL 5305: S, Z, E, AE, K, G, O; null when not declared |
| taxes[].rate_bp | integer | Basis points: 2200 = 22% |
| taxes[].amount | integer | Minor units of the currency |
| taxes[].exemption_reason | string · nullable · optional | BT-120, zero-rated only |
| taxes[].exemption_reason_code | string · nullable · optional | VATEX (BT-121), zero-rated only |
| created_at | string (date-time) | RFC 3339, UTC |
ChargeList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Charge | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
Adjustment
| Field | Type | Description |
|---|---|---|
| object | "adjustment" | |
| id | string (uuid) | |
| charge_id | string (uuid) | |
| customer_id | string (uuid) | |
| direction | "receivable" | |
| action | string · nullable | Open list of codes (see /codes) |
| reason | string · nullable | |
| category | string · nullable | |
| origin | string · nullable | HUMAN, SYSTEM, … |
| amount | integer | Signed: negative lowers the charge |
| consideration_effect | string changes · none | changes: a credit note (or debit note) follows; none: a credit loss, no tax |
| taxes | array of object | With changes: the tax difference, already computed. With none: empty |
| taxes[].type | "vat" | Open list: other types may come |
| taxes[].jurisdiction | string · nullable | ISO 3166-1 alpha-2 of the stable |
| taxes[].category | string · nullable | UNCL 5305: S, Z, E, AE, K, G, O; null when not declared |
| taxes[].rate_bp | integer | Basis points: 2200 = 22% |
| taxes[].amount | integer | Minor units of the currency |
| taxes[].exemption_reason | string · nullable · optional | BT-120, zero-rated only |
| taxes[].exemption_reason_code | string · nullable · optional | VATEX (BT-121), zero-rated only |
| taxable_amount | integer · nullable | Minor units of the currency (ISO 4217) |
| currency | string | |
| competence_month | string | YYYY-MM |
| accounting_month | string | YYYY-MM |
| occurred_at | string (date-time) | RFC 3339, UTC |
| reverses_adjustment_id | string (uuid) · nullable | |
| taxonomy_version | integer |
AdjustmentList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Adjustment | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
Allocation
| Field | Type | Description |
|---|---|---|
| object | "allocation" | |
| id | string (uuid) | |
| payment_id | string (uuid) | |
| charge_id | string (uuid) | |
| amount | integer | Signed |
| currency | string · optional | |
| consideration_effect | "none" |
Payment
| Field | Type | Description |
|---|---|---|
| object | "payment" | |
| id | string (uuid) | |
| customer_id | string (uuid) · nullable | |
| type | string payment · credit_applied · offset · refund · moved_to_credit · reversal | What happened to the money (open list) |
| amount | integer | The money that really moved, signed: a refund or a reversal is negative, moved_to_credit is zero |
| currency | string | |
| date | string (date) | YYYY-MM-DD |
| accounting_month | string | YYYY-MM |
| method | string | cash, bank_transfer, pos, credit, compensazione, other (open list) |
| reference | string · nullable | |
| paid_by | object · nullable | Who paid on behalf of the customer (a parent): not a customer of its own |
| paid_by.kind | string · nullable | |
| paid_by.name | string · nullable | |
| paid_by.tax_code | string · nullable · optional | customers.fiscal:read only |
| paid_by.address_text | string · nullable · optional | customers.fiscal:read only |
| reverses_payment_id | string (uuid) · nullable | |
| action | string · nullable | Reversals only |
| reason | string · nullable | |
| category | string · nullable | |
| consideration_effect | "none" | |
| allocations | array of Allocation | |
| taxonomy_version | integer · nullable | |
| created_at | string (date-time) | RFC 3339, UTC |
PaymentList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Payment | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
CreditEntry
| Field | Type | Description |
|---|---|---|
| object | "credit_entry" | |
| id | string (uuid) | |
| customer_id | string (uuid) | |
| direction | string credit · debit | credit: the credit is born or grows; debit: it is used or refunded |
| amount | integer | Always positive: direction says the way |
| currency | string | |
| source | string | Open list of codes |
| payment_id | string (uuid) · nullable | The movement that caused it |
| charge_id | string (uuid) · nullable | |
| action | string · nullable | |
| reason | string · nullable | |
| category | string · nullable | |
| reverses_entry_id | string (uuid) · nullable | |
| consideration_effect | "none" | |
| created_at | string (date-time) | RFC 3339, UTC |
CreditEntryList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of CreditEntry | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
Receipt
| Field | Type | Description |
|---|---|---|
| object | "receipt" | |
| id | string (uuid) | |
| kind | string payment_receipt · refund_confirmation | payment_receipt: series R, money received; refund_confirmation: series RB, money refunded (open list) |
| series | string | R, RB (open list): every series has its own progression |
| year | integer | |
| sequence | integer | Progressive number inside series and year, without gaps |
| number | string | The number as printed on the document |
| status | string issued · voided | A voided receipt stays, with its number |
| issued_at | string (date-time) | RFC 3339, UTC |
| voided_at | string (date-time) · nullable | RFC 3339, UTC |
| operation_type | string · nullable | Refund confirmations only: voluntary_refund, payment_reversal, chargeback (open list) |
| payment_id | string (uuid) · nullable | The payment, or the refund, that the receipt confirms |
| charge_id | string (uuid) · nullable | Only receipts of the old model, issued on a charge instead of a payment |
| customer_id | string (uuid) · nullable | |
| amount | integer · nullable | As frozen on the document, signed: a refund confirmation is negative |
| currency | string | |
| pdf_available | boolean | false only for the oldest receipts, issued before frozen documents: no sheet to print again |
| fiscal_document | "false" | A confirmation of payment: the fiscal document is issued by your software |
ReceiptList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Receipt | |
| has_more | boolean | There is a next page: ask again with starting_after = the id of the last item |
Event
| Field | Type | Description |
|---|---|---|
| object | "event" | |
| id | string (uuid) | Stable, unique across stables: use it to recognise an event you already processed |
| type | string | Open list: customer.updated, charge.created, charge.due_date_changed, charge.tax_changed, adjustment.created, payment.created, allocation.created, credit_entry.created, receipt.issued, receipt.voided |
| data | object | |
| data.object | string | Open list: customer, charge, adjustment, payment, allocation, credit_entry, receipt |
| data.id | string (uuid) | |
| data.url | string | Where to read it, from the host: /api/v1/charges/{id} |
| occurred_at | string (date-time) | When the fact happened: its creation, issue or void time; for a tax change, its creation |
| recorded_at | string (date-time) | When the event was written: for historical events, the day the history was loaded |
| historical | boolean | true: a fact from before the events existed, loaded once, ordered by its date |
EventList
| Field | Type | Description |
|---|---|---|
| object | "list" | |
| data | array of Event | |
| has_more | boolean | Ask again with after = next_cursor. A page can hold fewer events than limit, even none, while has_more is true |
| next_cursor | string (uuid) · nullable | Save it after processing the page, and pass it back as after. It can be the id of an event you are not shown. null only when the stable has no events for you yet |
Codes
| Field | Type | Description |
|---|---|---|
| object | "codes" | |
| language | string | The language of the names: ?lang=, then Accept-Language, then en |
| taxonomy_version | integer | The taxonomy that action, reason and category come from |
| lists | object | |
| lists.charge_type | object | |
| lists.charge_type.fields | array of string | Where these codes appear: resource.field |
| lists.charge_type.codes | array of object | |
| lists.charge_type.codes[].code | string | |
| lists.charge_type.codes[].name | string | |
| lists.action | object | |
| lists.action.fields | array of string | Where these codes appear: resource.field |
| lists.action.codes | array of object | |
| lists.action.codes[].code | string | |
| lists.action.codes[].name | string | |
| lists.reason | object | |
| lists.reason.fields | array of string | Where these codes appear: resource.field |
| lists.reason.codes | array of object | |
| lists.reason.codes[].code | string | |
| lists.reason.codes[].name | string | |
| lists.reason.codes[].action | string | The name of a reason depends on its action: look it up with both |
| lists.reason.codes[].category | string | |
| lists.category | object | |
| lists.category.fields | array of string | Where these codes appear: resource.field |
| lists.category.codes | array of object | |
| lists.category.codes[].code | string | |
| lists.category.codes[].name | string | |
| lists.origin | object | |
| lists.origin.fields | array of string | Where these codes appear: resource.field |
| lists.origin.codes | array of object | |
| lists.origin.codes[].code | string | |
| lists.origin.codes[].name | string | |
| lists.payment_type | object | |
| lists.payment_type.fields | array of string | Where these codes appear: resource.field |
| lists.payment_type.codes | array of object | |
| lists.payment_type.codes[].code | string | |
| lists.payment_type.codes[].name | string | |
| lists.payment_method | object | |
| lists.payment_method.fields | array of string | Where these codes appear: resource.field |
| lists.payment_method.codes | array of object | |
| lists.payment_method.codes[].code | string | |
| lists.payment_method.codes[].name | string | |
| lists.credit_source | object | |
| lists.credit_source.fields | array of string | Where these codes appear: resource.field |
| lists.credit_source.codes | array of object | |
| lists.credit_source.codes[].code | string | |
| lists.credit_source.codes[].name | string | |
| lists.receipt_kind | object | |
| lists.receipt_kind.fields | array of string | Where these codes appear: resource.field |
| lists.receipt_kind.codes | array of object | |
| lists.receipt_kind.codes[].code | string | |
| lists.receipt_kind.codes[].name | string | |
| lists.refund_operation | object | |
| lists.refund_operation.fields | array of string | Where these codes appear: resource.field |
| lists.refund_operation.codes | array of object | |
| lists.refund_operation.codes[].code | string | |
| lists.refund_operation.codes[].name | string | |
| lists.tax_category | object | UNCL 5305 |
| lists.tax_category.fields | array of string | Where these codes appear: resource.field |
| lists.tax_category.codes | array of object | |
| lists.tax_category.codes[].code | string | |
| lists.tax_category.codes[].name | string | |
| lists.unit | object | UNECE Rec. 20 |
| lists.unit.fields | array of string | Where these codes appear: resource.field |
| lists.unit.codes | array of object | |
| lists.unit.codes[].code | string | |
| lists.unit.codes[].name | string | |
| lists.event_type | object | |
| lists.event_type.fields | array of string | Where these codes appear: resource.field |
| lists.event_type.codes | array of object | |
| lists.event_type.codes[].code | string | |
| lists.event_type.codes[].name | string |