Accounting platforms
One API over Dinero and e-conomic: what is identical, the fields that name a platform's own choice, and what a platform can refuse.
A key is bound to one connected company, and that company keeps its books in one accounting system: Dinero or e-conomic. Which one it is, is not something your integration has to know.
Every endpoint under /api/v1 behaves the same on either: the same request
bodies, the same response shapes, the same status codes and the same error
codes. No field, no code and no message of the API names a platform. You write
the integration once, and it keeps working for a company on the other system.
This page is where the two are named, because the few differences below are yours to act on.
What stays the same
- Field names.
platform_refandplatform_numberon an invoice, a credit note and an accrual entry are the handle and the number the accounting system gave the booked document, whichever system that is. - Error codes.
PLATFORM_API_ERRORis the502for an accounting system that could not be reached or did not answer. A refusal by the accounting system is data underrefusal, with a reason code of Tabba's own and the platform's words beside it. send_error.nullon a document whose delivery succeeded, and an object with areasonand the platform's own words (platform_reason) when the document was booked and its delivery is not known to have succeeded.- Amounts, dates, currencies, recognition and the month-end accrual are Tabba's own arithmetic and are identical by construction.
Ids are the platform's handles
A customer's and a product's id is the handle the accounting system knows
the record by: a GUID on Dinero, the customer or product number on e-conomic.
Treat it as opaque text. It is not always a UUID, and a number can be given to
another record once its own is deleted in the accounting system.
Address records by your own external_id and you never depend on the handle:
see external_id and idempotency.
Fields that name a platform's own choice
A few fields of a customer and a product name an entry of a list the accounting system keeps, or a fact only one system holds.
| Field | On Dinero | On e-conomic |
|---|---|---|
vat_zone_ref (customer) | not kept | required: the VAT zone the customer is placed in |
customer_group_ref (customer) | not kept | required: the customer group the customer is filed in |
payment_terms_ref (customer) | not kept | an entry of the company's list of payment terms |
layout_ref (customer) | not kept | the customer's document layout |
payment_mean (customer) | required when send_method is einvoice | not asked for |
invoice_mail_out_option_key (customer) | VAT, GLN, SE or P | GLN |
account_ref (product) | the account number as text, and may be left out | the number of the product group the revenue is filed in |
Where a required value is missing, the write is answered 422 with
VALIDATION_FAILED, and field_errors carries a code under the field's name:
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_FAILED",
"message": "The customer failed validation.",
"field_errors": {
"vat_zone_ref": ["VAT_ZONE_REQUIRED"],
"customer_group_ref": ["CUSTOMER_GROUP_REQUIRED"]
},
"request_id": "req_…"
}
}To find valid values, read a customer or a product the company already has
(GET /customers, GET /products): each states the references the
accounting system holds for it.
Two rules keep a sync that does not model these fields from moving a record:
POST /customersunder anexternal_idthat is taken keepsvat_zone_ref,payment_terms_ref,layout_refandcustomer_group_refas they are when the body leaves them out.POST /productsunder anexternal_idthat is taken keepsaccount_refwhen the body leaves it out andaccount_numberis unchanged.
A product whose account_ref names no product group of the company is refused
by the platform, with the reason under refusal.
What a platform can refuse
| Code | Status | What happened |
|---|---|---|
PLATFORM_REFUSED | 422 | The accounting system refused the write of a customer or a product. Nothing was written. refusal says why. |
ISSUE_REFUSED | 422 | The accounting system refused to book an invoice. Nothing was booked. |
CREDIT_REFUSED | 422 | The accounting system refused to book a credit note. Nothing was booked. |
PLATFORM_NOT_CONFIGURED | 409 | The company's connection is missing a setting the write needs. Nothing about your request is wrong: an admin completes the setup in the workspace. |
PLATFORM_UNAVAILABLE | 409 | The company has no accounting system to write to. |
PLATFORM_API_ERROR | 502 | The accounting system could not be reached, or did not answer. It may or may not hold the change. |
A refusal is not an outage. Do not retry a 422 with the same body: read
refusal.reason and refusal.platform_reason, and correct the record. Retry a
502 with backoff. A create sent under an external_id is safe to send again
unchanged within the hour: see
external_id and idempotency.
E-invoices
A customer whose send_method is einvoice states how it is routed, in
invoice_mail_out_option_key, and the identifier that channel reads. The
channels a platform can route are in the table above. A channel the company's
platform cannot route is refused when the customer is written, as
VALIDATION_FAILED with MAILOUT_OPTION_UNAVAILABLE under
invoice_mail_out_option_key.
The delivery channel is checked again when an invoice is issued, before
anything is booked: a customer that cannot be sent to is refused with
INVALID_SEND_METHOD, and one that lacks its e-invoice details with
MISSING_EINVOICE_DETAILS. Both are 422, and in both the fix is on the
customer.
Differences that never reach a refusal
- A credit note on e-conomic is a booked invoice with negative amounts.
Crediting works on both platforms and
POST /credit-notesis identical. What differs is the document that lands in the books. - e-conomic sends a document as part of booking it, and keeps no readable
record of a send. A document booked there therefore states
send_error: null. On Dinero the send is a step of its own after the booking, and a failed one is reported insend_error. - A booked document cannot be sent again through the API, on either platform. Following up on a failed delivery is done in the workspace.