{"openapi":"3.1.0","info":{"title":"Tabba Sales API","version":"1.0.0","description":"The REST API of the Tabba Sales module: customers, products, invoices and revenue recognition for one company, from your own tooling. Authenticate with an API key (`Authorization: Bearer tba_…`) that an admin mints under Settings → Developers. A key reaches exactly one company. Changes within `/api/v1` are additive."},"servers":[{"url":"https://www.tabba.io/api/v1","description":"Production"}],"tags":[{"name":"accruals"},{"name":"config"},{"name":"credit-notes"},{"name":"customers"},{"name":"invoices"},{"name":"products"},{"name":"recognition"},{"name":"recurring-series"},{"name":"users"},{"name":"webhooks"},{"name":"work-registrations"}],"paths":{"/config":{"get":{"operationId":"getConfig","summary":"Read the configuration of the company the key is bound to","description":"The base currency every figure is stated in, and the two accounts the month-end accrual moves. Both accounts are null until an admin has confirmed them.","tags":["config"],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"config"},"integration_id":{"type":"string","description":"The company the key is bound to."},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"base_currency":{"type":"string","description":"ISO 4217. Every figure of the company is stated in it."},"wip_account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The work-in-progress account the month-end accrual moves, once confirmed."},"deferred_revenue_account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The deferred-revenue account the month-end accrual moves, once confirmed."}},"required":["object","integration_id","company_name","base_currency","wip_account_number","deferred_revenue_account_number"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/users":{"get":{"operationId":"getUsers","summary":"List the people of the company","description":"Everyone who can open the key's company, each with their role in it, oldest change first: the organisation admins and every member of the company. Read-only: people are invited, removed and given a role in the workspace.","tags":["users"],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"external_id","in":"query","required":false,"description":"Only the record that carries this external id.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. To follow a list, ask from the newest `updated_at` you were answered: that record comes again, with everything changed after it.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"user"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the person."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["organisation_admin","admin","bookkeeper","auditor","standard"],"description":"The person's role in the key's company: `organisation_admin` (admin of every company of the organisation), `admin`, `bookkeeper` (an admin who does not manage people), `auditor` (reads everything, writes nothing, holds no line) or `standard` (works on their own lines)."},"default_hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The rate a new hourly line is pre-filled with for the person."},"updated_at":{"type":"string","description":"When the profile last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","email","role","default_hourly_rate","updated_at"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/users/{ref}":{"get":{"operationId":"getUsersRef","summary":"Read one person of the company","tags":["users"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key. A person is also named by `email:<address>`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"user"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the person."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["organisation_admin","admin","bookkeeper","auditor","standard"],"description":"The person's role in the key's company: `organisation_admin` (admin of every company of the organisation), `admin`, `bookkeeper` (an admin who does not manage people), `auditor` (reads everything, writes nothing, holds no line) or `standard` (works on their own lines)."},"default_hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The rate a new hourly line is pre-filled with for the person."},"updated_at":{"type":"string","description":"When the profile last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","email","role","default_hourly_rate","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"patch":{"operationId":"patchUsersRef","summary":"Set or clear a person's external_id","description":"The `external_id` is the only field of a person a key may write. It is unique in the account: one that another person carries is refused with `DUPLICATE_EXTERNAL_ID`.","tags":["users"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key. A person is also named by `email:<address>`.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]}},"required":["external_id"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"user"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the person."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["organisation_admin","admin","bookkeeper","auditor","standard"],"description":"The person's role in the key's company: `organisation_admin` (admin of every company of the organisation), `admin`, `bookkeeper` (an admin who does not manage people), `auditor` (reads everything, writes nothing, holds no line) or `standard` (works on their own lines)."},"default_hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The rate a new hourly line is pre-filled with for the person."},"updated_at":{"type":"string","description":"When the profile last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","email","role","default_hourly_rate","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/customers":{"get":{"operationId":"getCustomers","summary":"List the customers the company invoices","description":"Oldest change first. `updated_since` narrows the list to what changed at or after an instant. A change is stamped as it is written, in the order changes become visible, so a list followed from the newest `updated_at` it answered misses nothing and needs no overlap. A change of `external_id` alone is not such a change.","tags":["customers"],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"external_id","in":"query","required":false,"description":"Only the record that carries this external id.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. To follow a list, ask from the newest `updated_at` you were answered: that record comes again, with everything changed after it.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"post":{"operationId":"postCustomers","summary":"Create a customer, or update the one that carries the external_id","description":"The customer is written to the accounting platform first. With an `external_id` that a customer already carries, that customer is updated and the answer is 200; otherwise a customer is created and the answer is 201. An update replaces what the body states and keeps a choice from the platform's own lists (`vat_zone_ref`, `payment_terms_ref`, `layout_ref`, `customer_group_ref`) that the body leaves out. One create runs at a time under an `external_id`: a second while the first is still running is answered 409 `CREATE_IN_PROGRESS` with `Retry-After`, and the same request after that interval answers the customer the first created. A create under an `external_id` is safe to send again after a 502: where the first request made the customer, the same request, with the same body and within the hour, is answered that customer. A create with no `external_id` sent again makes a second customer. Where the platform made the customer and the create did not finish, the answer is 502 `CREATE_UNFINISHED` with the customer's `record_id`: the customer is in the catalog, and the same request again updates it.","tags":["customers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"country_key":{"type":"string"},"is_person":{"type":"boolean"},"send_method":{"type":"string","enum":["email","einvoice"]},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string","enum":["EmptyCompanyType","SoleProprietorship","PrivateLimitedCompany","PublicLimitedCompany","GeneralPartnership","LimitedPartnership","LimitedLiabilityCooperative","LimitedLiabilityVoluntaryAssociation","LimitedLiabilityCompany","EntreprenurLimitedCompany","Union","VoluntaryUnion","SmallPersonallyOwnedCompany","TrustFund","Others"]},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string","enum":["da","en","de","sv","no"]},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_type":{"anyOf":[{"type":"string","enum":["Netto","NettoCash","CurrentMonthOut"]},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string","enum":["VAT","GLN","SE","P"]},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_id":{"description":"Your own key. A create under one that is taken updates that customer.","type":"string","minLength":1,"maxLength":255}},"required":["name","country_key","is_person","send_method"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at"],"additionalProperties":false}}}},"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/customers/{ref}":{"get":{"operationId":"getCustomersRef","summary":"Read one customer","tags":["customers"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"patch":{"operationId":"patchCustomersRef","summary":"Change the fields of a customer that the body states","description":"A field the body leaves out stays as it is; a field stated as `null` is cleared. The change is written to the accounting platform first. A body that states only `external_id` asks the platform nothing.","tags":["customers"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"country_key":{"type":"string"},"is_person":{"type":"boolean"},"send_method":{"type":"string","enum":["email","einvoice"]},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string","enum":["EmptyCompanyType","SoleProprietorship","PrivateLimitedCompany","PublicLimitedCompany","GeneralPartnership","LimitedPartnership","LimitedLiabilityCooperative","LimitedLiabilityVoluntaryAssociation","LimitedLiabilityCompany","EntreprenurLimitedCompany","Union","VoluntaryUnion","SmallPersonallyOwnedCompany","TrustFund","Others"]},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string","enum":["da","en","de","sv","no"]},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_type":{"anyOf":[{"type":"string","enum":["Netto","NettoCash","CurrentMonthOut"]},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string","enum":["VAT","GLN","SE","P"]},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_id":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]},"delete":{"operationId":"deleteCustomersRef","summary":"Delete a customer","description":"Refused with `DELETE_BLOCKED_BY_REFERENCES` (409) while an invoice, a recurring series or a credit note of the company names the customer: the platform is then not asked. Refused with `DELETE_BLOCKED_BY_BOOKINGS` (409) when the accounting platform holds bookings against the customer. Either way nothing is deleted.","tags":["customers"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["object","id","deleted"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/products":{"get":{"operationId":"getProducts","summary":"List the products the company offers","description":"Oldest change first. `updated_since` narrows the list to what changed at or after an instant. A change is stamped as it is written, in the order changes become visible, so a list followed from the newest `updated_at` it answered misses nothing and needs no overlap. A change of `external_id` alone is not such a change.","tags":["products"],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"external_id","in":"query","required":false,"description":"Only the record that carries this external id.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. To follow a list, ask from the newest `updated_at` you were answered: that record comes again, with everything changed after it.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"post":{"operationId":"postProducts","summary":"Create a product, or update the one that carries the external_id","description":"The product is written to the accounting platform first. With an `external_id` that a product already carries, that product is updated and the answer is 200; otherwise a product is created and the answer is 201. A product number names one product: where the platform already holds a product under the number, that product is answered with 200 and nothing is written to it. One create runs at a time under an `external_id`: a second while the first is still running is answered 409 `CREATE_IN_PROGRESS` with `Retry-After`, and the same request after that interval answers the product the first created.","tags":["products"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_number":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"account_number":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"unit":{"type":"string","minLength":1},"quantity":{"default":1,"type":"number","exclusiveMinimum":0},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]},"default_price":{"type":"number","minimum":0},"external_id":{"description":"Your own key. A create under one that is taken updates that product.","type":"string","minLength":1,"maxLength":255}},"required":["product_number","name","account_number","unit","default_price"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at"],"additionalProperties":false}}}},"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/products/{ref}":{"get":{"operationId":"getProductsRef","summary":"Read one product","tags":["products"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"patch":{"operationId":"patchProductsRef","summary":"Change the fields of a product that the body states","description":"A field the body leaves out stays as it is. The change is written to the accounting platform first. A body that states only `external_id` asks the platform nothing.","tags":["products"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_number":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"account_number":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"unit":{"type":"string","minLength":1},"quantity":{"type":"number","exclusiveMinimum":0},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]},"default_price":{"type":"number","minimum":0},"external_id":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]},"delete":{"operationId":"deleteProductsRef","summary":"Delete a product","description":"Refused with `DELETE_BLOCKED_BY_REFERENCES` (409) while a line of an invoice, a recurring series or a credit note of the company names the product: the platform is then not asked. Refused with `DELETE_BLOCKED_BY_BOOKINGS` (409) when the accounting platform holds bookings against the product. Either way nothing is deleted.","tags":["products"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["object","id","deleted"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/invoices":{"get":{"operationId":"getInvoices","summary":"List the invoices of the company","description":"Every invoice, a draft or issued, the occurrences of recurring series among them (each states its `series_id`). Oldest change first. `updated_since` narrows the list to what changed at or after an instant; the stamp is taken when the invoice is written, so a list is followed from the instant the last walk started, with no overlap.","tags":["invoices"],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"external_id","in":"query","required":false,"description":"Only the record that carries this external id.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. The stamp is taken when the record is written, so a list is followed from the instant the last walk started: no overlap is needed.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"customer","in":"query","required":false,"description":"Only invoices of this customer: its `id`, or `ext:<external_id>`.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"status","in":"query","required":false,"description":"Only drafts, or only issued invoices.","schema":{"type":"string","enum":["draft","issued"]}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"post":{"operationId":"postInvoices","summary":"Create a draft invoice, or replace the draft that carries the external_id","description":"A draft is Tabba’s own record: nothing is asked of the accounting platform until the invoice is issued. With an `external_id` no invoice carries, a draft is created and the answer is 201. With one a draft carries, that draft is replaced and the answer is 200: a line that states its `id` stays the line it was, with the work registered on it; a line that states none is new; a line the body leaves out is removed. Two creates under one `external_id` at the same moment make one invoice: the second is answered that invoice, or 409 `CREATE_IN_PROGRESS` with `Retry-After` while the first is still writing it. An `external_id` an ISSUED invoice carries is refused with `INVOICE_ALREADY_ISSUED` (409): an issued invoice is frozen, and a credit note is the way to change it.","tags":["invoices"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":255,"description":"Your own key. A create under one that is taken replaces that draft."},"customer":{"type":"string","minLength":1,"maxLength":255,"description":"The customer billed: its `id`, or `ext:<external_id>`."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"ISO 4217."},"issue_date":{"description":"YYYY-MM-DD. Null or left out: the invoice is issued once all its work is complete.","anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"auto_send":{"description":"Left out: on for a new invoice, and as it was for one that is replaced.","type":"boolean"},"lines":{"maxItems":200,"type":"array","items":{"type":"object","properties":{"id":{"description":"The line of this invoice the entry replaces. It keeps its id and the work registered on it.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"product":{"type":"string","minLength":1,"maxLength":255,"description":"The product billed: its `id`, or `ext:<external_id>`."},"recognition_method":{"type":"string","enum":["value","hourly"],"description":"`value`: a fixed amount, recognised by completion. `hourly`: registered hours at each person’s rate."},"agreed_value":{"description":"What a value line bills before VAT and before its discount. Not stated on an hourly line.","anyOf":[{"type":"number"},{"type":"null"}]},"discount":{"description":"A percentage off the line.","anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"description":"The line's own text. Left out, the document prints the product's name.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"position":{"description":"Where the line stands among the lines. Left out, the order of the request.","type":"integer","minimum":0,"maximum":9007199254740991},"assignees":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"user":{"type":"string","minLength":1,"maxLength":255,"description":"The person: their `id`, `ext:<external_id>` or `email:<address>`."},"distribution_percentage":{"description":"The person's share of a value line, as a fraction in [0, 1]. The shares on a line sum to 1. Left out on every person of a line, the line is split evenly. Not read on an hourly line.","type":"number"},"hourly_rate_override":{"description":"The person's rate on an hourly line. Required there, and refused on a value line.","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["user"]},"description":"The people who work on the line."}},"required":["product","recognition_method","assignees"]}}},"required":["external_id","customer","currency","lines"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/invoices/{ref}":{"get":{"operationId":"getInvoicesRef","summary":"Read one invoice","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"put":{"operationId":"putInvoicesRef","summary":"Replace a draft invoice","description":"The body is the whole draft. A line that states its `id` stays the line it was, with the work registered on it; a line that states none is new; a line of the invoice the body leaves out is removed. `external_id` left out stays as it is, and `null` clears it; `auto_send` left out stays as it is. Refused with `INVOICE_ALREADY_ISSUED` (409) once the invoice is issued, with `ISSUE_IN_PROGRESS` (409) while an issue attempt holds it, and with `INVOICE_IS_OCCURRENCE` (409) for an occurrence of a recurring series, which is changed through its series.","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]},"customer":{"type":"string","minLength":1,"maxLength":255,"description":"The customer billed: its `id`, or `ext:<external_id>`."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"ISO 4217."},"issue_date":{"description":"YYYY-MM-DD. Null or left out: the invoice is issued once all its work is complete.","anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"auto_send":{"description":"Left out: on for a new invoice, and as it was for one that is replaced.","type":"boolean"},"lines":{"maxItems":200,"type":"array","items":{"type":"object","properties":{"id":{"description":"The line of this invoice the entry replaces. It keeps its id and the work registered on it.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"product":{"type":"string","minLength":1,"maxLength":255,"description":"The product billed: its `id`, or `ext:<external_id>`."},"recognition_method":{"type":"string","enum":["value","hourly"],"description":"`value`: a fixed amount, recognised by completion. `hourly`: registered hours at each person’s rate."},"agreed_value":{"description":"What a value line bills before VAT and before its discount. Not stated on an hourly line.","anyOf":[{"type":"number"},{"type":"null"}]},"discount":{"description":"A percentage off the line.","anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"description":"The line's own text. Left out, the document prints the product's name.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"position":{"description":"Where the line stands among the lines. Left out, the order of the request.","type":"integer","minimum":0,"maximum":9007199254740991},"assignees":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"user":{"type":"string","minLength":1,"maxLength":255,"description":"The person: their `id`, `ext:<external_id>` or `email:<address>`."},"distribution_percentage":{"description":"The person's share of a value line, as a fraction in [0, 1]. The shares on a line sum to 1. Left out on every person of a line, the line is split evenly. Not read on an hourly line.","type":"number"},"hourly_rate_override":{"description":"The person's rate on an hourly line. Required there, and refused on a value line.","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["user"]},"description":"The people who work on the line."}},"required":["product","recognition_method","assignees"]}}},"required":["customer","currency","lines"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]},"delete":{"operationId":"deleteInvoicesRef","summary":"Delete a draft invoice","description":"The draft goes with its lines and the work registered on them. Refused with `INVOICE_ALREADY_ISSUED` (409) once the invoice is issued, and with `INVOICE_IS_OCCURRENCE` (409) for an occurrence of a recurring series.","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["object","id","deleted"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/invoices/{ref}/issue":{"post":{"operationId":"postInvoicesRefIssue","summary":"Issue an invoice now","description":"The accounting platform books and sends the invoice inside the request, and the answer is the issued invoice. It is the explicit \"bill this one now\": an invoice set not to send is issued all the same, and one with no date, or a date ahead, is dated today. **Sending it again is safe**: an invoice that is issued already is answered as it stands, 200, and nothing is booked twice. **A document that booked and could not be delivered is a 200** whose `send_error` says why: the invoice is in the books, so do not issue it again. Only a refusal to book is an error: `ISSUE_REFUSED` (422) carries the platform’s reason under `refusal`; `HOURLY_INCOMPLETE` and `NOTHING_TO_BILL` (409) say an hourly line is not ready; `CUSTOMER_GONE` and `PRODUCT_GONE` (409) that the platform no longer holds what the invoice names; `ISSUE_IN_PROGRESS` (409, with `Retry-After`) that another attempt holds the invoice. Metered against the `platform_write` bucket as well as `default`.","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default","platform_write"]}},"/invoices/{ref}/recognition":{"get":{"operationId":"getInvoicesRefRecognition","summary":"Read the revenue recognition of one invoice","description":"Earned, billed, deferred revenue and work in progress, per line and for the invoice, in the company’s base currency. The figures are the month-end accrual’s own, stated as of the last day of `month`: the running month where it is left out.","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"month","in":"query","required":false,"description":"YYYY-MM: the month the figures are stated as of, at its last day. Left out: the running month, as it stands today.","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice_recognition"},"invoice_id":{"type":"string"},"customer_id":{"type":"string"},"currency":{"type":"string","description":"The company's base currency: every figure is in it."},"month":{"type":"string","description":"The month the figures are stated as of: its first day."},"earned":{"type":"number","description":"What the work registered has earned."},"billed":{"type":"number","description":"What issued invoices have billed, net of booked credit notes."},"deferred":{"type":"number","description":"Billed ahead of the work: deferred revenue."},"wip":{"type":"number","description":"Earned ahead of the invoice: work in progress."},"missing_rates":{"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string"},"currency":{"type":"string","description":"The line's currency."},"at":{"type":"string","description":"What the rate was needed for: a work month (YYYY-MM) or an issue day (YYYY-MM-DD)."}},"required":["invoice_line_id","currency","at"],"additionalProperties":false},"description":"The rates foreign-currency lines needed and did not get. Not empty: the totals leave those lines out."},"lines":{"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string"},"description":{"type":"string","description":"The line's own text, else its product's name."},"recognition_method":{"type":"string","enum":["value","hourly"]},"earned":{"anyOf":[{"type":"number","description":"What the work registered has earned."},{"type":"null"}]},"billed":{"anyOf":[{"type":"number","description":"What issued invoices have billed, net of booked credit notes."},{"type":"null"}]},"deferred":{"anyOf":[{"type":"number","description":"Billed ahead of the work: deferred revenue."},{"type":"null"}]},"wip":{"anyOf":[{"type":"number","description":"Earned ahead of the invoice: work in progress."},{"type":"null"}]}},"required":["invoice_line_id","description","recognition_method","earned","billed","deferred","wip"],"additionalProperties":false}}},"required":["object","invoice_id","customer_id","currency","month","earned","billed","deferred","wip","missing_rates","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/invoices/{ref}/credit-notes":{"get":{"operationId":"getInvoicesRefCreditNotes","summary":"List the credit notes booked against an invoice","description":"Only booked credit notes are listed, those a recurring series’ end booked among them: an attempt that did not book is no credit. Oldest change first; the stamp is taken when the credit note is written, so `updated_since` needs no overlap.","tags":["invoices"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. The stamp is taken when the record is written, so a list is followed from the instant the last walk started: no overlap is needed.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"credit_note"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the credit note."},"invoice_id":{"type":"string","description":"The issued invoice the credit note takes back."},"customer_id":{"type":"string","description":"The customer's `id`."},"currency":{"type":"string","description":"The invoice's currency: a credit note is raised in it."},"kind":{"type":"string","enum":["full","partial"],"description":"`full`: the whole invoice is taken back. `partial`: the lines say what is."},"origin":{"type":"string","enum":["manual","series_end"],"description":"`manual`: raised by a person or through this API. `series_end`: booked when a recurring series ended."},"credit_date":{"type":"string","description":"The date the credit is booked on."},"issued_at":{"type":"string","description":"When the platform booked the credit note."},"platform_ref":{"type":"string","description":"The accounting platform's handle for the booked credit note."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked credit note."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"total_amount":{"type":"number","description":"What was taken back, before VAT: the sum of the lines."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the credit note last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoice_line_id":{"type":"string","description":"The line of the invoice the amount is taken off."},"amount":{"type":"number","description":"Before VAT, in the invoice’s currency."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","invoice_line_id","amount","position"],"additionalProperties":false}}},"required":["object","id","external_id","invoice_id","customer_id","currency","kind","origin","credit_date","issued_at","platform_ref","platform_number","send_error","total_amount","created_at","updated_at","lines"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/credit-notes":{"post":{"operationId":"postCreditNotes","summary":"Credit an issued invoice, in full or in part","description":"The accounting platform books and sends the credit note inside the request, and the answer is the booked credit note, 201. A full credit takes the whole invoice back and is refused once anything was credited (`INVOICE_ALREADY_CREDITED`); a partial credit names lines of the invoice, each by no more than is left on it (`VALIDATION_FAILED` with `AMOUNT_EXCEEDS_BILLED` under the line). Amounts are before VAT. **Sending it again is safe**: the same `external_id` is the same credit note, whatever its body says the second time. Booked, it is answered as it stands, 200, and nothing is booked twice; not booked, that attempt is taken up again under its own date and lines. **A credit note that booked and could not be delivered is a success** whose `send_error` says why. An attempt the platform gave no definite answer to holds every other credit on the invoice back (`CREDIT_ATTEMPT_UNRESOLVED`, 409) until the request that made it is sent again. Metered against the `platform_write` bucket as well as `default`.","tags":["credit-notes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":255,"description":"Your own key. A create under one that is taken is the same credit note: nothing is booked twice."},"invoice":{"type":"string","minLength":1,"maxLength":255,"description":"The issued invoice to credit: its `id`, or `ext:<external_id>`."},"kind":{"type":"string","enum":["full","partial"]},"credit_date":{"type":"string","description":"YYYY-MM-DD: the date the credit is booked on."},"lines":{"description":"For a partial credit: at least one line, each once. Not read for a full credit.","maxItems":200,"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string","description":"A line of the invoice."},"amount":{"type":"number","description":"What to take off the line, before VAT. At most what is left on it."}},"required":["invoice_line_id","amount"]}}},"required":["external_id","invoice","kind","credit_date"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"credit_note"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the credit note."},"invoice_id":{"type":"string","description":"The issued invoice the credit note takes back."},"customer_id":{"type":"string","description":"The customer's `id`."},"currency":{"type":"string","description":"The invoice's currency: a credit note is raised in it."},"kind":{"type":"string","enum":["full","partial"],"description":"`full`: the whole invoice is taken back. `partial`: the lines say what is."},"origin":{"type":"string","enum":["manual","series_end"],"description":"`manual`: raised by a person or through this API. `series_end`: booked when a recurring series ended."},"credit_date":{"type":"string","description":"The date the credit is booked on."},"issued_at":{"type":"string","description":"When the platform booked the credit note."},"platform_ref":{"type":"string","description":"The accounting platform's handle for the booked credit note."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked credit note."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"total_amount":{"type":"number","description":"What was taken back, before VAT: the sum of the lines."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the credit note last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoice_line_id":{"type":"string","description":"The line of the invoice the amount is taken off."},"amount":{"type":"number","description":"Before VAT, in the invoice’s currency."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","invoice_line_id","amount","position"],"additionalProperties":false}}},"required":["object","id","external_id","invoice_id","customer_id","currency","kind","origin","credit_date","issued_at","platform_ref","platform_number","send_error","total_amount","created_at","updated_at","lines"],"additionalProperties":false}}}},"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"credit_note"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the credit note."},"invoice_id":{"type":"string","description":"The issued invoice the credit note takes back."},"customer_id":{"type":"string","description":"The customer's `id`."},"currency":{"type":"string","description":"The invoice's currency: a credit note is raised in it."},"kind":{"type":"string","enum":["full","partial"],"description":"`full`: the whole invoice is taken back. `partial`: the lines say what is."},"origin":{"type":"string","enum":["manual","series_end"],"description":"`manual`: raised by a person or through this API. `series_end`: booked when a recurring series ended."},"credit_date":{"type":"string","description":"The date the credit is booked on."},"issued_at":{"type":"string","description":"When the platform booked the credit note."},"platform_ref":{"type":"string","description":"The accounting platform's handle for the booked credit note."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked credit note."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"total_amount":{"type":"number","description":"What was taken back, before VAT: the sum of the lines."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the credit note last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoice_line_id":{"type":"string","description":"The line of the invoice the amount is taken off."},"amount":{"type":"number","description":"Before VAT, in the invoice’s currency."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","invoice_line_id","amount","position"],"additionalProperties":false}}},"required":["object","id","external_id","invoice_id","customer_id","currency","kind","origin","credit_date","issued_at","platform_ref","platform_number","send_error","total_amount","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default","platform_write"]}},"/recurring-series":{"get":{"operationId":"getRecurringSeries","summary":"List the recurring series of the company","description":"Oldest change first. A series that has ended is still `active`: a series ends by date, and has no cancelled state. `updated_since` narrows the list to what changed at or after an instant; the stamp is taken when the series is written, so a list is followed from the instant the last walk started, with no overlap. A change to a line alone does not move the stamp.","tags":["recurring-series"],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"external_id","in":"query","required":false,"description":"Only the record that carries this external id.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"updated_since","in":"query","required":false,"description":"Only records changed at or after this ISO 8601 instant. The stamp is taken when the record is written, so a list is followed from the instant the last walk started: no overlap is needed.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"customer","in":"query","required":false,"description":"Only series of this customer: its `id`, or `ext:<external_id>`.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","active"]}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"post":{"operationId":"postRecurringSeries","summary":"Create a recurring series, or save the header of the one that carries the external_id","description":"A series is Tabba’s own record: nothing is asked of the accounting platform until one of its occurrences is issued. With an `external_id` no series carries, the series is created active with its lines, each complete, and the answer is 201; occurrences whose period has started are invoices at once. With one a series carries, the header of that series is saved, as `PATCH` saves it, and the answer is 200: **its lines are left as they are**. A line has a timeline of its own, so the lines of a series that exists are changed through the line routes. Two creates under one `external_id` at the same moment make one series.","tags":["recurring-series"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":255,"description":"Your own key. A create under one that is taken saves the header of that series and leaves its lines."},"customer":{"type":"string","minLength":1,"maxLength":255,"description":"The customer billed: its `id`, or `ext:<external_id>`."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"YYYY-MM-DD."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"YYYY-MM-DD, inclusive, or null for no end."},"issue_timing":{"description":"Left out: at the start of each period.","oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"]}]},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean"},"layout_ref":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"lines":{"maxItems":200,"type":"array","items":{"type":"object","properties":{"product":{"type":"string","minLength":1,"maxLength":255,"description":"The product billed: its `id`, or `ext:<external_id>`."},"recognition_method":{"type":"string","enum":["value","hourly"],"description":"`value`: a fixed amount, recognised by completion. `hourly`: registered hours at each person’s rate."},"agreed_value":{"description":"What a value line bills before VAT and before its discount. Not stated on an hourly line.","anyOf":[{"type":"number"},{"type":"null"}]},"discount":{"description":"A percentage off the line.","anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"description":"The line's own text. Left out, the document prints the product's name.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"position":{"description":"Where the line stands among the lines. Left out, the order of the request.","type":"integer","minimum":0,"maximum":9007199254740991},"assignees":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"user":{"type":"string","minLength":1,"maxLength":255,"description":"The person: their `id`, `ext:<external_id>` or `email:<address>`."},"distribution_percentage":{"description":"The person's share of a value line, as a fraction in [0, 1]. The shares on a line sum to 1. Left out on every person of a line, the line is split evenly. Not read on an hourly line.","type":"number"},"hourly_rate_override":{"description":"The person's rate on an hourly line. Required there, and refused on a value line.","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["user"]},"description":"The people who work on the line."}},"required":["product","recognition_method","assignees"]},"description":"The recurring lines the series starts with: at least one, each complete. Not read for a series that exists."}},"required":["external_id","customer","currency","frequency","start_date","lines"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines"],"additionalProperties":false}}}},"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}":{"get":{"operationId":"getRecurringSeriesRef","summary":"Read one recurring series","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]},"patch":{"operationId":"patchRecurringSeriesRef","summary":"Change the header fields of a recurring series that the body states","description":"A field the body leaves out stays as it is. The lines are not touched, except that a change of `start_date` or `frequency` moves every period and so resets each line to what it started with. Once the series has issued an invoice its customer, currency, schedule and title are locked (`SERIES_SETUP_LOCKED`, 409); `layout_ref` never is. Moving `end_date` on such a series ends it by that date, exactly as the cancel route does, with the credit notes an end books; the cancel route is the one that reports them. A schedule that leaves out occurrences with registered work is refused (`SCHEDULE_DROPS_REGISTERED_WORK`, 409) until the body states `acknowledge_dropped_work`, and a change met by an occurrence that is being issued is refused whole (`ISSUE_IN_PROGRESS`, 409).","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer":{"type":"string","minLength":1,"maxLength":255,"description":"The customer billed: its `id`, or `ext:<external_id>`."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"YYYY-MM-DD."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"YYYY-MM-DD, inclusive, or null for no end."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"]}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean"},"layout_ref":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"external_id":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]},"acknowledge_dropped_work":{"description":"True: occurrences the change leaves out are dropped with the work registered on them. Without it such a change is refused with `SCHEDULE_DROPS_REGISTERED_WORK`.","type":"boolean"}}}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/cancel":{"post":{"operationId":"postRecurringSeriesRefCancel","summary":"Cancel a recurring series: set its end date","description":"A series ends by date, and there is no cancelled state. The series bills up to `end_date`: the un-issued occurrence the date falls in is cut and prorated, un-issued occurrences past it are dropped, and what was ISSUED past it is handed back with credit notes. Those are queued and booked by a job, so the request does not wait for the platform: `credit_notes` lists each as it stands (`queued`, or `booked`). An end set to today or to a day that has passed issues the occurrences that are due at once. A series that has not started and has issued nothing is deleted instead (`discarded`). The body may be left out. **Sending the same end date again is safe**: it is never refused, writes no second credit note, states the credit notes as they now stand, and has any that is not booked attempted again. A different date is refused once the end has passed (`END_HAS_PASSED`) or a credit note has settled it (`END_CREDITED`).","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"end_date":{"description":"YYYY-MM-DD: the last billed day. Left out: the last day of the billing period that holds today.","type":"string"},"acknowledge_dropped_work":{"description":"True: occurrences the change leaves out are dropped with the work registered on them. Without it such a change is refused with `SCHEDULE_DROPS_REGISTERED_WORK`.","type":"boolean"}}}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"recurring_series"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the series."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the series kept it."},"currency":{"type":"string","description":"ISO 4217."},"frequency":{"type":"string","enum":["monthly","quarterly","semi-annual","annual"]},"start_date":{"type":"string","description":"The first day of the first billing period, and the anchor of every later one."},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last billed day, inclusive. Null: the series runs on."},"issue_timing":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"start-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"end-of-period"}},"required":["mode"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"custom"},"day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The day of the month, 1 to 31; a shorter month issues on its last day."},"month_offset":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many months after the period's first month. At or past the period's length bills in arrears."}},"required":["mode","day","month_offset"],"additionalProperties":false}],"description":"When in its period an occurrence is issued. Never later than the end date of the series."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_billing_period_as_title":{"type":"boolean","description":"On: each occurrence is titled with its billing period, in the customer's invoice language."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","active"],"description":"`draft`: nothing is invoiced from it yet. `active`: its occurrences become invoices. A series that ended stays `active`."},"cancelled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When an end was decided for a series that was running."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the series last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The recurring line. The line routes and a work registration name it by this."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"The recurring lines, each as the series started with it. An occurrence states what it bills."},"discarded":{"type":"boolean","description":"True when the series had not started and had issued nothing: it is deleted, and the series stated is as it was."},"unchanged":{"type":"boolean","description":"True when the series already had this end date."},"credit_notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoice_id":{"type":"string","description":"The issued occurrence the credit note takes back."},"state":{"type":"string","enum":["queued","unresolved","refused","booked","handled"],"description":"`queued`: the platform has not been asked yet. `booked`: the platform holds it. `unresolved` and `refused`: an attempt did not book; asking for the same end again attempts it again. `handled`: settled outside Tabba."}},"required":["id","invoice_id","state"],"additionalProperties":false},"description":"Every credit note the series' end has, as each stands now."},"dropped_occurrences":{"type":"array","items":{"type":"object","properties":{"period_from":{"type":"string"},"period_to":{"type":"string"},"work_registrations":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Work registrations that went with the occurrence."}},"required":["period_from","period_to","work_registrations"],"additionalProperties":false},"description":"The un-issued occurrences past the end that this request deleted."}},"required":["object","id","external_id","customer_id","customer_name","currency","frequency","start_date","end_date","issue_timing","title","use_billing_period_as_title","layout_ref","status","cancelled_at","created_at","updated_at","lines","discarded","unchanged","credit_notes","dropped_occurrences"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/lines":{"post":{"operationId":"postRecurringSeriesRefLines","summary":"Add a line to a recurring series","description":"With `this-and-following` the line is a recurring one from the occurrence `period` names (the start of the series where it is left out): earlier occurrences never see it. With `this-only` it is a one-time line on that one occurrence. The line is placed after the lines the occurrence has: a new line never moves one that was there. Occurrences that are already invoices, and not issued, follow the change. **Not idempotent**: a line carries no key of its own, and adding twice adds two.","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["this-and-following","this-only"],"description":"`this-and-following`: from the occurrence `period` names, onward. `this-only`: on that occurrence alone."},"period":{"description":"The occurrence the line is on, or starts from: the first day of its billing period. Left out with `this-and-following`: the start of the series. Required with `this-only`.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"line":{"type":"object","properties":{"product":{"type":"string","minLength":1,"maxLength":255,"description":"The product billed: its `id`, or `ext:<external_id>`."},"recognition_method":{"type":"string","enum":["value","hourly"],"description":"`value`: a fixed amount, recognised by completion. `hourly`: registered hours at each person’s rate."},"agreed_value":{"description":"What a value line bills before VAT and before its discount. Not stated on an hourly line.","anyOf":[{"type":"number"},{"type":"null"}]},"discount":{"description":"A percentage off the line.","anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"description":"The line's own text. Left out, the document prints the product's name.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"assignees":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"user":{"type":"string","minLength":1,"maxLength":255,"description":"The person: their `id`, `ext:<external_id>` or `email:<address>`."},"distribution_percentage":{"description":"The person's share of a value line, as a fraction in [0, 1]. The shares on a line sum to 1. Left out on every person of a line, the line is split evenly. Not read on an hourly line.","type":"number"},"hourly_rate_override":{"description":"The person's rate on an hourly line. Required there, and refused on a value line.","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["user"]},"description":"The people who work on the line."}},"required":["product","recognition_method","assignees"]}},"required":["scope","line"]}}}},"responses":{"201":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"series_line"},"id":{"type":"string"},"kind":{"type":"string","enum":["series","one_time"],"description":"`series`: a recurring line. `one_time`: a line on one occurrence alone."},"scope":{"type":"string","enum":["this-and-following","this-only"],"description":"`this-and-following`: from the occurrence `period` names, onward. `this-only`: on that occurrence alone."},"period":{"type":"string","description":"The occurrence the change holds from."},"series_status":{"type":"string","enum":["draft","active"],"description":"The status of the series after the change."}},"required":["object","id","kind","scope","period","series_status"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/lines/{lineRef}":{"patch":{"operationId":"patchRecurringSeriesRefLinesLineRef","summary":"Change a line of a recurring series","description":"The fields the body states are changed as the line stands on the occurrence `period` names. With `this-and-following` the change holds from that occurrence on, and earlier occurrences keep what they had. With `this-only` it holds on that occurrence alone, and what the line says before and after is left as it is. The result is what the same edit in the workspace leaves: on the first occurrence every change is the line’s own start, whatever scope is asked; the product always holds from the occurrence on; and a field an occurrence already states for itself stays its own until that field is changed for this and following. A one-time line is on one occurrence, so either scope changes it in place. The same change sent again writes nothing more. Refused with `OCCURRENCE_ISSUED` (409) when the occurrence is issued, and with `SERIES_LINE_NOT_FOUND` (404) when the line is not on that occurrence.","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"lineRef","in":"path","required":true,"description":"The `id` of a recurring line, or the `line_id` of a one-time line as its occurrence states it.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["this-and-following","this-only"],"description":"`this-and-following`: from the occurrence `period` names, onward. `this-only`: on that occurrence alone."},"period":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The occurrence the change holds from: the first day of its billing period, YYYY-MM-DD."},"line":{"type":"object","properties":{"product":{"type":"string","minLength":1,"maxLength":255,"description":"The product billed: its `id`, or `ext:<external_id>`."},"recognition_method":{"type":"string","enum":["value","hourly"],"description":"`value`: a fixed amount, recognised by completion. `hourly`: registered hours at each person’s rate."},"agreed_value":{"description":"What a value line bills before VAT and before its discount. Not stated on an hourly line.","anyOf":[{"type":"number"},{"type":"null"}]},"discount":{"description":"A percentage off the line.","anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"description":"The line's own text. Left out, the document prints the product's name.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"assignees":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"user":{"type":"string","minLength":1,"maxLength":255,"description":"The person: their `id`, `ext:<external_id>` or `email:<address>`."},"distribution_percentage":{"description":"The person's share of a value line, as a fraction in [0, 1]. The shares on a line sum to 1. Left out on every person of a line, the line is split evenly. Not read on an hourly line.","type":"number"},"hourly_rate_override":{"description":"The person's rate on an hourly line. Required there, and refused on a value line.","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["user"]},"description":"The people who work on the line."}},"description":"A field left out stays as the occurrence has it. `assignees`, where stated, is the whole roster."}},"required":["scope","period","line"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"series_line"},"id":{"type":"string"},"kind":{"type":"string","enum":["series","one_time"],"description":"`series`: a recurring line. `one_time`: a line on one occurrence alone."},"scope":{"type":"string","enum":["this-and-following","this-only"],"description":"`this-and-following`: from the occurrence `period` names, onward. `this-only`: on that occurrence alone."},"period":{"type":"string","description":"The occurrence the change holds from."},"series_status":{"type":"string","enum":["draft","active"],"description":"The status of the series after the change."}},"required":["object","id","kind","scope","period","series_status"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]},"delete":{"operationId":"deleteRecurringSeriesRefLinesLineRef","summary":"Take a line of a recurring series away","description":"With `this-and-following` the line stops from the occurrence `period` names; earlier occurrences keep it. With `this-only` it is absent from that one occurrence. A one-time line is removed under either scope. Refused with `DELETE_EMPTIES_OCCURRENCE` (409) when it would leave an occurrence that is already an invoice with no lines, and with `OCCURRENCE_ISSUED` (409) when the occurrence is issued.","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"lineRef","in":"path","required":true,"description":"The `id` of a recurring line, or the `line_id` of a one-time line as its occurrence states it.","schema":{"type":"string"}},{"name":"scope","in":"query","required":true,"description":"`this-and-following`: from the occurrence `period` names, onward. `this-only`: on that occurrence alone.","schema":{"type":"string","enum":["this-and-following","this-only"]}},{"name":"period","in":"query","required":true,"description":"The occurrence the change holds from: the first day of its billing period, YYYY-MM-DD.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"series_line"},"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["object","id","deleted"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/occurrences":{"get":{"operationId":"getRecurringSeriesRefOccurrences","summary":"List the occurrences of a recurring series","description":"In the order of their periods, from the start of the series, or from `from`, to its end date, or to `to`. A series with no end date has no last occurrence: the list is walked a page at a time. Reading an occurrence never makes it an invoice.","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records a page holds. Default 25, at most 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","minLength":1}},{"name":"from","in":"query","required":false,"description":"Only occurrences whose period starts on or after this day. Default: the start of the series.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Only occurrences whose period starts on or before this day.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"occurrence"},"series_id":{"type":"string"},"period":{"type":"string","description":"What the occurrence is named by: the first day of its billing period."},"period_from":{"type":"string"},"period_to":{"type":"string","description":"The last billed day. Cut short by the end date of the series on its last period."},"issue_date":{"type":"string","description":"The day the occurrence is issued: the schedule's, or the invoice's own once it is one."},"is_final_partial":{"type":"boolean","description":"True when the end date of the series cut the period short."},"proration_factor":{"type":"number","description":"The share of a whole period a value line bills: 1, or less on a final partial period."},"status":{"type":"string","enum":["scheduled","issued","skipped"],"description":"`scheduled`: not issued yet, an invoice or not. `issued`: booked on the platform. `skipped`: left out by an admin."},"invoice_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The invoice the occurrence is, once it is one."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The title the occurrence carries, or will carry as an invoice."}},"required":["object","series_id","period","period_from","period_to","issue_date","is_final_partial","proration_factor","status","invoice_id","title"],"additionalProperties":false}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/occurrences/{period}":{"get":{"operationId":"getRecurringSeriesRefOccurrencesPeriod","summary":"Read one occurrence of a recurring series","description":"The occurrence with its lines. One that is not issued states what the series’ lines come to on it after every change, with a final partial period’s value lines prorated; one that is issued states the lines its invoice was issued with. **Reading it never makes it an invoice**: an occurrence that is none yet answers `invoice_id: null`. A date that starts no period of the series is `OCCURRENCE_OUT_OF_RANGE` (404).","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"period","in":"path","required":true,"description":"The first day of the occurrence’s billing period, YYYY-MM-DD, as a list of occurrences states it.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"occurrence"},"series_id":{"type":"string"},"period":{"type":"string","description":"What the occurrence is named by: the first day of its billing period."},"period_from":{"type":"string"},"period_to":{"type":"string","description":"The last billed day. Cut short by the end date of the series on its last period."},"issue_date":{"type":"string","description":"The day the occurrence is issued: the schedule's, or the invoice's own once it is one."},"is_final_partial":{"type":"boolean","description":"True when the end date of the series cut the period short."},"proration_factor":{"type":"number","description":"The share of a whole period a value line bills: 1, or less on a final partial period."},"status":{"type":"string","enum":["scheduled","issued","skipped"],"description":"`scheduled`: not issued yet, an invoice or not. `issued`: booked on the platform. `skipped`: left out by an admin."},"invoice_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The invoice the occurrence is, once it is one."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The title the occurrence carries, or will carry as an invoice."},"lines":{"type":"array","items":{"type":"object","properties":{"line_id":{"type":"string","description":"The recurring line, or one-time line, of the series. The line routes name it by this."},"kind":{"type":"string","enum":["series","one_time"],"description":"`series`: a recurring line. `one_time`: a line on this occurrence alone."},"invoice_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The line on the occurrence's invoice, once it is one."},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}}},"required":["line_id","kind","invoice_line_id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees"],"additionalProperties":false},"description":"What the occurrence bills."}},"required":["object","series_id","period","period_from","period_to","issue_date","is_final_partial","proration_factor","status","invoice_id","title","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/recurring-series/{ref}/occurrences/{period}/issue":{"post":{"operationId":"postRecurringSeriesRefOccurrencesPeriodIssue","summary":"Issue an occurrence of a recurring series now","description":"The occurrence is made an invoice if it is not one yet, and that invoice is issued as `POST /invoices/{ref}/issue` issues one: the answer is the issued invoice, sending it again is safe, and a document that booked and could not be delivered is a 200 carrying `send_error`. An occurrence made an invoice by an attempt that did not book stays an invoice, and the next attempt issues that one. Refused with `OCCURRENCE_SKIPPED` (409) for an occurrence an admin skipped, `SERIES_NOT_ACTIVE` (409) for a draft series and `OCCURRENCE_HAS_NO_LINES` (422) where the series states no line for the occurrence. Metered against the `platform_write` bucket as well as `default`.","tags":["recurring-series"],"parameters":[{"name":"ref","in":"path","required":true,"description":"The record's `id`, or `ext:<external_id>` for the record that carries your own key.","schema":{"type":"string"}},{"name":"period","in":"path","required":true,"description":"The first day of the occurrence’s billing period, YYYY-MM-DD, as a list of occurrences states it.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default","platform_write"]}},"/work-registrations":{"put":{"operationId":"putWorkRegistrations","summary":"Set a person’s hours and completion on a line","description":"Both figures are stated as they now stand: `hours` is the person’s total on the line, and `completion_rate` the completion they stand at. The total is registered as the signed difference against what is registered, in the entry month of the request (Europe/Copenhagen): the one bucket per line, person and month the workspace reads. **Sending the same figures again registers nothing.** Name the line on an invoice (`invoice` and the invoice line’s id) or on an occurrence of a recurring series (`series`, `occurrence` and the series line’s id): an occurrence that is no invoice yet is made one first. Set one person’s hours on one line one request at a time: two requests at the same moment both measure against the same total. Refused with `NOT_ASSIGNED` (409) when the person holds no place on the line, and with `HOURS_BILLED_LOCKED` (409) for the hours of an hourly line its invoice has billed.","tags":["work-registrations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"invoice":{"description":"The invoice the line is on: its `id`, or `ext:<external_id>`.","type":"string","minLength":1,"maxLength":255},"series":{"description":"The recurring series the line is of: its `id`, or `ext:<external_id>`. With `occurrence`.","type":"string","minLength":1,"maxLength":255},"occurrence":{"description":"The occurrence of the series: the first day of its billing period, YYYY-MM-DD.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"line":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"With `invoice`: the invoice line's `id`. With `series`: the `id` of the recurring line, or of a one-time line."},"user":{"type":"string","minLength":1,"maxLength":255,"description":"Whose work it is: their `id`, `ext:<external_id>` or `email:<address>`."},"hours":{"description":"The person's total hours on the line. Null or left out: the hours stay as they are. One request raises a total by at most 1000 hours, a guard against a slipped decimal (`HOURS_CHANGE_TOO_LARGE`).","anyOf":[{"type":"number","minimum":0,"maximum":1000000},{"type":"null"}]},"completion_rate":{"description":"The completion the person now stands at, as a fraction in [0, 1]. Null or left out: it stays as it is.","anyOf":[{"type":"number","minimum":0,"maximum":1},{"type":"null"}]},"external_id":{"description":"Your own key for the month's registration.","anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}]}},"required":["line","user"]}}}},"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"work_registration"},"invoice_id":{"type":"string","description":"The invoice the line is on. For an occurrence: the invoice it is, made now if it was none."},"invoice_line_id":{"type":"string"},"user_id":{"type":"string"},"accrual_month":{"type":"string","description":"The entry month the write landed in: its first day, in Europe/Copenhagen."},"hours":{"type":"number","description":"The person's total hours on the line after the request."},"hours_delta":{"type":"number","description":"What the request registered: the signed difference against what was registered. 0 when nothing moved."},"completion_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The person's latest completion on the line after the request."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","invoice_id","invoice_line_id","user_id","accrual_month","hours","hours_delta","completion_rate","external_id"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read_write","x-rate-limit-buckets":["default"]}},"/recognition":{"get":{"operationId":"getRecognition","summary":"Read the revenue recognition of one customer","description":"Earned, billed, deferred revenue and work in progress over every line of every invoice of the customer, drafts and occurrences of recurring series among them, in the company’s base currency. The figures are the month-end accrual’s own, stated as of the last day of `month`: the running month where it is left out. Deferred revenue and work in progress are stated per line and summed, so a customer can carry both.","tags":["recognition"],"parameters":[{"name":"customer","in":"query","required":true,"description":"The customer: its `id`, or `ext:<external_id>`.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"month","in":"query","required":false,"description":"YYYY-MM: the month the figures are stated as of, at its last day. Left out: the running month, as it stands today.","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"customer_recognition"},"customer_id":{"type":"string"},"currency":{"type":"string","description":"The company's base currency: every figure is in it."},"month":{"type":"string","description":"The month the figures are stated as of: its first day."},"earned":{"type":"number","description":"What the work registered has earned."},"billed":{"type":"number","description":"What issued invoices have billed, net of booked credit notes."},"deferred":{"type":"number","description":"Billed ahead of the work: deferred revenue."},"wip":{"type":"number","description":"Earned ahead of the invoice: work in progress."},"missing_rates":{"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string"},"currency":{"type":"string","description":"The line's currency."},"at":{"type":"string","description":"What the rate was needed for: a work month (YYYY-MM) or an issue day (YYYY-MM-DD)."}},"required":["invoice_line_id","currency","at"],"additionalProperties":false},"description":"The rates foreign-currency lines needed and did not get. Not empty: the totals leave those lines out."}},"required":["object","customer_id","currency","month","earned","billed","deferred","wip","missing_rates"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}},"/accruals":{"get":{"operationId":"getAccruals","summary":"Read the accrual entry of one customer for one month","description":"Where the month-end accrual stands for the customer in that month: a draft kept current while the month runs, or the entry the close booked. Answered `NOT_FOUND` (404) where the customer has no entry for the month: nothing moved for them in it, or the company’s two accrual accounts are not confirmed.","tags":["accruals"],"parameters":[{"name":"customer","in":"query","required":true,"description":"The customer: its `id`, or `ext:<external_id>`.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"month","in":"query","required":true,"description":"YYYY-MM: the month the entry closes.","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"accrual"},"id":{"type":"string"},"customer_id":{"type":"string"},"accrual_month":{"type":"string","description":"The month the entry closes: its first day."},"original_accrual_month":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The earliest month this entry carries because the platform had closed that month. Null: it carries none."},"status":{"type":"string","enum":["draft","booked","self_healed"],"description":"`draft`: kept current while the month runs. `booked`: posted by the month-end close. `self_healed`: the platform had closed the month, and a later month carries it."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the draft or booked entry, where it holds one."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number the platform stamped on the booked entry, where it stamps one."},"booked_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"line_targets":{"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string"},"target":{"type":"number","description":"Billed less earned: positive is deferred revenue, negative is work in progress."}},"required":["invoice_line_id","target"],"additionalProperties":false},"description":"What the entry moves each invoice line to, in the base currency."}},"required":["object","id","customer_id","accrual_month","original_accrual_month","status","platform_ref","platform_number","booked_at","line_targets"],"additionalProperties":false}}}},"400":{"description":"The request is malformed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"The API key is missing, unknown or revoked. A request that names no key of ours is metered by its client address, in the `unauthenticated` bucket of `x-rate-limits`, and this answer states what is left of that budget.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The key lacks the scope the endpoint needs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The company holds no such record.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"The request runs into the state of the record. See `code`. Three codes carry `Retry-After`, each because another request is still at work on the same record: `CREATE_IN_PROGRESS` (a create under the `external_id`), `ISSUE_IN_PROGRESS` (an issue of the invoice) and `CREDIT_IN_PROGRESS` (a credit of the invoice).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"The request failed validation, or the platform refused it. See `field_errors` and `refusal`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"The key is over its rate limit, or the client address is over the `unauthenticated` bucket with a request that names no key of ours. Retry after `Retry-After` seconds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"An error on our side.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"The accounting platform could not be reached, or did not answer (`PLATFORM_API_ERROR`): it may or may not hold the change. A create sent under an `external_id` is safe to send again unchanged within the hour, and one sent without is not. Or the platform made the record and the create did not finish (`CREATE_UNFINISHED`): the record is `record_id`, and the same request again under its `external_id`, or a patch by that id, finishes it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-scope":"read","x-rate-limit-buckets":["default"]}}},"webhooks":{"invoice.issued":{"post":{"operationId":"onInvoiceIssued","summary":"An invoice was issued","description":"The accounting platform booked the invoice: by the daily run, by an admin at the desk, or by a call to the issue route. Sent once per invoice. `data` is the invoice as `GET /invoices/{ref}` answers it.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"invoice.issued"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}},"invoice.send_failed":{"post":{"operationId":"onInvoiceSendFailed","summary":"An issued invoice was not sent","description":"The invoice was booked, and its delivery to the customer is not known to have succeeded. Sent beside `invoice.issued`, never instead of it. `data.send_error` says why. The invoice is in the books: follow up on the delivery, and do not issue it again.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"invoice.send_failed"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"type":"object","properties":{"object":{"type":"string","const":"invoice"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the invoice."},"customer_id":{"type":"string","description":"The customer's `id`."},"customer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The customer's name as the invoice kept it."},"currency":{"type":"string","description":"ISO 4217."},"issue_date":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The date the invoice is booked and sent on. Null: issued once all its work is complete."},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"auto_send":{"type":"boolean","description":"On: the daily run issues the invoice on its issue date."},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["draft","issued"]},"issued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the platform booked the invoice."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the booked document."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked document."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"series_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The recurring series the invoice is an occurrence of, if it is one."},"period_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, first day."},"period_to":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An occurrence's billing period, last day."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the invoice last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string","description":"The product's `id`."},"product_number":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's number as the line kept it."},"product_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The product's name as the line kept it."},"recognition_method":{"type":"string","enum":["value","hourly"]},"agreed_value":{"anyOf":[{"type":"number"},{"type":"null"}]},"hourly_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"An hourly line's rate, derived from the rates of the people on it."},"discount":{"anyOf":[{"type":"number"},{"type":"null"}]},"description_override":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"assignees":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","description":"The person's id. For a member since removed, the id they had."},"distribution_percentage":{"type":"number"},"hourly_rate_override":{"anyOf":[{"type":"number"},{"type":"null"}]},"removed":{"type":"boolean","description":"True when the member was removed from the account: the place waits to be reassigned."}},"required":["user_id","distribution_percentage","hourly_rate_override","removed"],"additionalProperties":false}},"series_line_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"On an occurrence of a recurring series: the series line, or one-time line, the line came from."}},"required":["id","product_id","product_number","product_name","recognition_method","agreed_value","hourly_rate","discount","description_override","position","assignees","series_line_id"],"additionalProperties":false}}},"required":["object","id","external_id","customer_id","customer_name","currency","issue_date","title","auto_send","layout_ref","status","issued_at","platform_ref","platform_number","send_error","series_id","period_from","period_to","created_at","updated_at","lines"],"additionalProperties":false}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}},"credit_note.issued":{"post":{"operationId":"onCreditNoteIssued","summary":"A credit note was booked","description":"The accounting platform booked a credit note: one an admin or a key asked for, or one a recurring series' end queued. Sent once per credit note.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"credit_note.issued"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"type":"object","properties":{"object":{"type":"string","const":"credit_note"},"id":{"type":"string"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the credit note."},"invoice_id":{"type":"string","description":"The issued invoice the credit note takes back."},"customer_id":{"type":"string","description":"The customer's `id`."},"currency":{"type":"string","description":"The invoice's currency: a credit note is raised in it."},"kind":{"type":"string","enum":["full","partial"],"description":"`full`: the whole invoice is taken back. `partial`: the lines say what is."},"origin":{"type":"string","enum":["manual","series_end"],"description":"`manual`: raised by a person or through this API. `series_end`: booked when a recurring series ended."},"credit_date":{"type":"string","description":"The date the credit is booked on."},"issued_at":{"type":"string","description":"When the platform booked the credit note."},"platform_ref":{"type":"string","description":"The accounting platform's handle for the booked credit note."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number a person reads on the booked credit note."},"send_error":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the delivery failed, as a code of Tabba's own."},"platform_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The platform's own words, where it gave any."}},"required":["reason","platform_reason"],"additionalProperties":false},{"type":"null"}],"description":"Set when the document is booked and its delivery is not known to have succeeded. The document stays booked: do not issue it again."},"total_amount":{"type":"number","description":"What was taken back, before VAT: the sum of the lines."},"created_at":{"type":"string"},"updated_at":{"type":"string","description":"When the credit note last changed, as `updated_since` reads it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoice_line_id":{"type":"string","description":"The line of the invoice the amount is taken off."},"amount":{"type":"number","description":"Before VAT, in the invoice’s currency."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","invoice_line_id","amount","position"],"additionalProperties":false}}},"required":["object","id","external_id","invoice_id","customer_id","currency","kind","origin","credit_date","issued_at","platform_ref","platform_number","send_error","total_amount","created_at","updated_at","lines"],"additionalProperties":false}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}},"customer.updated":{"post":{"operationId":"onCustomerUpdated","summary":"A customer changed","description":"A customer was created, changed, switched off or deleted, in Tabba or on the accounting platform, where a change is seen at the next import. `data` is the customer as `GET /customers/{ref}` answers it, with `archived_at` and `deleted_at`. Two changes in quick succession may both carry the later state.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"customer.updated"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"anyOf":[{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string","description":"The accounting platform's handle for the customer. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the customer."},"name":{"type":"string"},"country_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 3166-1 alpha-2."},"is_person":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"send_method":{"type":"string","enum":["email","einvoice"],"description":"How an issued invoice reaches the customer."},"street":{"anyOf":[{"type":"string"},{"type":"null"}]},"zip_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"webpage":{"anyOf":[{"type":"string"},{"type":"null"}]},"att_person":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"se_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"p_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"ean_number":{"anyOf":[{"type":"string"},{"type":"null"}]},"use_cvr":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"company_type_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_language_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferred_invoice_currency_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"payment_condition_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_condition_number_of_days":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"invoice_mail_out_option_key":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_mean":{"anyOf":[{"type":"string"},{"type":"null"}]},"vat_zone_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"payment_terms_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"layout_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"customer_group_ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the customer last changed, as `updated_since` reads it."},"archived_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the accounting platform stopped offering the record: switched off, or deleted. Null while it offers it. The API lists and reads only records that carry none."},"deleted_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the accounting platform stopped holding the record. Null while it holds it. A deleted record has no `external_id`: the id is free for another record."}},"required":["object","id","external_id","name","country_key","is_person","send_method","street","zip_code","city","phone","email","webpage","att_person","vat_number","se_number","p_number","ean_number","use_cvr","company_type_key","preferred_invoice_language_key","preferred_invoice_currency_key","external_reference","payment_condition_type","payment_condition_number_of_days","invoice_mail_out_option_key","payment_mean","vat_zone_ref","payment_terms_ref","layout_ref","customer_group_ref","updated_at","archived_at","deleted_at"],"additionalProperties":false},{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string"},"external_id":{"type":"null"},"archived_at":{"type":"string"},"deleted_at":{"type":"string"}},"required":["object","id","external_id","archived_at","deleted_at"],"additionalProperties":false,"description":"A deleted customer of which Tabba holds nothing but its `id`."}]}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}},"product.updated":{"post":{"operationId":"onProductUpdated","summary":"A product changed","description":"A product was created, changed, switched off or deleted, in Tabba or on the accounting platform, where a change is seen at the next import. `data` is the product as `GET /products/{ref}` answers it, with `archived_at` and `deleted_at`.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"product.updated"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"anyOf":[{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"The accounting platform's handle for the product. Opaque."},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own key for the product."},"product_number":{"type":"string"},"name":{"type":"string"},"account_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The revenue account a line billing the product posts to."},"account_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the account was chosen as, in the platform's own list."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_price":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Price per unit, excluding VAT."},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Default quantity of a line billing the product."},"comments":{"anyOf":[{"type":"string"},{"type":"null"}]},"external_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's own reference field. Not `external_id`."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the product last changed, as `updated_since` reads it."},"archived_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the accounting platform stopped offering the record: switched off, or deleted. Null while it offers it. The API lists and reads only records that carry none."},"deleted_at":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the accounting platform stopped holding the record. Null while it holds it. A deleted record has no `external_id`: the id is free for another record."}},"required":["object","id","external_id","product_number","name","account_number","account_ref","unit","default_price","quantity","comments","external_reference","updated_at","archived_at","deleted_at"],"additionalProperties":false},{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string"},"external_id":{"type":"null"},"archived_at":{"type":"string"},"deleted_at":{"type":"string"}},"required":["object","id","external_id","archived_at","deleted_at"],"additionalProperties":false,"description":"A deleted product of which Tabba holds nothing but its `id`."}]}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}},"accrual.booked":{"post":{"operationId":"onAccrualBooked","summary":"A month-end accrual entry was booked","description":"The month-end close posted a customer's accrual entry. Not sent for a month the platform had closed, which a later month carries. `data` is the entry as `GET /accruals` answers it.","tags":["webhooks"],"security":[],"parameters":[{"name":"Tabba-Signature","in":"header","required":true,"description":"`t=<unix seconds>,v1=<hex>`: `v1` is the HMAC-SHA256, in hex, of `<t>.<body>` under the endpoint's signing secret, where `<body>` is the request body byte for byte. Verify it before you trust the body, and refuse a `t` more than 300 seconds from your own clock. A retry and a replay carry the same body under a new signature.","schema":{"type":"string"}},{"name":"Tabba-Event-Id","in":"header","required":true,"description":"The event's `id`, as in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"event"},"id":{"type":"string","pattern":"^evt_[0-9a-f]{32}$","description":"The same for every endpoint the event went to and for every retry and replay of it. Delivery is at least once: tell a repeat by this id."},"type":{"type":"string","const":"accrual.booked"},"created_at":{"type":"string","description":"When the event was announced."},"data":{"type":"object","properties":{"object":{"type":"string","const":"accrual"},"id":{"type":"string"},"customer_id":{"type":"string"},"accrual_month":{"type":"string","description":"The month the entry closes: its first day."},"original_accrual_month":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The earliest month this entry carries because the platform had closed that month. Null: it carries none."},"status":{"type":"string","enum":["draft","booked","self_healed"],"description":"`draft`: kept current while the month runs. `booked`: posted by the month-end close. `self_healed`: the platform had closed the month, and a later month carries it."},"platform_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The accounting platform's handle for the draft or booked entry, where it holds one."},"platform_number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The number the platform stamped on the booked entry, where it stamps one."},"booked_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"line_targets":{"type":"array","items":{"type":"object","properties":{"invoice_line_id":{"type":"string"},"target":{"type":"number","description":"Billed less earned: positive is deferred revenue, negative is work in progress."}},"required":["invoice_line_id","target"],"additionalProperties":false},"description":"What the entry moves each invoice line to, in the base currency."}},"required":["object","id","customer_id","accrual_month","original_accrual_month","status","platform_ref","platform_number","booked_at","line_targets"],"additionalProperties":false}},"required":["object","id","type","created_at","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"You took the event. Answer within ten seconds. A 5xx, a 408, a 429 or no answer is tried again, eight times over about sixteen hours; any other status fails the delivery at once, and a redirect is not followed. An endpoint whose host resolves to an address that is not public is never connected to. An admin can replay a delivery under Settings → Developers."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key (tba_…)","description":"An API key minted by an admin under Settings → Developers. It is bound to one company and has a scope: `read`, or `read_write`. A request without one, or with one that is not ours, is answered 401 and metered by its client address (`x-rate-limits`)."}},"schemas":{"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["api_error","authentication_error","invalid_request_error","permission_error","rate_limit_error"]},"code":{"type":"string","description":"A stable code to branch on. Today one of: BAD_REQUEST, CREATE_IN_PROGRESS, CREATE_UNFINISHED, CREDIT_ATTEMPT_UNRESOLVED, CREDIT_IN_PROGRESS, CREDIT_REFUSED, CUSTOMER_GONE, DB_ERROR, DELETE_BLOCKED_BY_BOOKINGS, DELETE_BLOCKED_BY_REFERENCES, DELETE_EMPTIES_OCCURRENCE, DUPLICATE_EXTERNAL_ID, DUPLICATE_PRODUCT_NUMBER, END_BEFORE_START, END_BLOCKED_BY_CREDIT, END_CREDITED, END_HAS_PASSED, HOURLY_INCOMPLETE, HOURS_BILLED_LOCKED, INTERNAL_ERROR, INVALID_API_KEY, INVALID_SEND_METHOD, INVOICE_ALREADY_CREDITED, INVOICE_ALREADY_ISSUED, INVOICE_IS_OCCURRENCE, INVOICE_NOT_FOUND, INVOICE_NOT_ISSUED, ISSUE_IN_PROGRESS, ISSUE_REFUSED, LINE_NOT_FOUND, MIRROR_WRITE_FAILED, MISSING_EINVOICE_DETAILS, MISSING_LINES, NOTHING_TO_BILL, NOTHING_TO_CREDIT, NOT_ASSIGNED, NOT_FOUND, OCCURRENCE_HAS_NO_LINES, OCCURRENCE_ISSUED, OCCURRENCE_OUT_OF_RANGE, OCCURRENCE_SKIPPED, PLATFORM_API_ERROR, PLATFORM_NOT_CONFIGURED, PLATFORM_REFUSED, PLATFORM_UNAVAILABLE, PRODUCT_GONE, RATE_LIMITED, RECORD_ARCHIVED, REGISTRATION_FAILED, SCHEDULE_DROPS_REGISTERED_WORK, SCOPE_INSUFFICIENT, SERIES_END_CONFLICT, SERIES_LINE_NOT_FOUND, SERIES_NOT_ACTIVE, SERIES_NOT_FOUND, SERIES_SETUP_LOCKED, UNAUTHORIZED, VALIDATION_FAILED. Codes are added, never renamed."},"message":{"type":"string","description":"English, for a log or a developer. Not for an end user."},"field_errors":{"type":"object","description":"Per field of the request, the codes of what to fix.","additionalProperties":{"type":"array","items":{"type":"string"}}},"refusal":{"type":"object","description":"Why the accounting platform refused, where it did; on `CREATE_UNFINISHED`, what of the create it did not finish.","properties":{"reason":{"type":"string"},"params":{"type":"object","additionalProperties":true},"platform_reason":{"type":["string","null"],"description":"The platform's own words, where it gave any."}},"required":["reason","params","platform_reason"]},"record_id":{"type":"string","description":"On `CREATE_UNFINISHED`: the `id` of the record the request did create. It is in the catalog, and a patch by this id finishes it."},"request_id":{"type":"string"}},"required":["type","code","message","request_id"]}},"required":["error"]}},"headers":{"X-Request-Id":{"description":"The id of this request. Quote it when you ask about a call.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests the tightest bucket of this call allows per window, per key. Buckets: `default`: 300 per 60 s; `platform_write`: 30 per 60 s. On an answer to a request that names no key of ours: per client address, `unauthenticated`: 60 per 60 s.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"When the window has room again, in seconds since the epoch.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}}}},"security":[{"bearerAuth":[]}],"x-rate-limits":{"default":{"limit":300,"window_seconds":60,"per":"key","description":"Every operation."},"platform_write":{"limit":30,"window_seconds":60,"per":"key","description":"On top of `default`, for an operation that makes the accounting platform book something."},"unauthenticated":{"limit":60,"window_seconds":60,"per":"client_address","description":"A request with no API key, or with one that is not ours, on any operation. Past the limit it is answered 429 `RATE_LIMITED` with `Retry-After` in place of the 401. A request under a live key is not counted here, whatever else its address sends: a key is told apart from its minting on, or failing that from the first request it is accepted on. A revoked key is counted here."}}}