Billberry Client API
Using Billberry's client API, you can send e-invoices on behalf of your companies and download received e-invoices. You can, for example, automate sending e-invoices through an e-commerce platform or another web service. Additionally you can use the API seamlessly with accounting software to send and receive e-invoices through Billberry.
Both Billberry and its API are free to use. If you don't have an account yet, please sign up.
Through the client interface, you can only send e-invoices for your own companies. If you wish to send e-invoices on behalf of your clients without them having to be Billberry clients, you can become a Billberry partner. Check out the Billberry Partner API guide and get in touch.
General
Billberry's API is based on HTTP and follows the REST principles. It follows a resource-based address structure, semantic error codes, versioning with MIME types, and prefers functionality defined in HTTP over custom alternatives.
- Billberry's API URL
https://api.billberry.ee
You can find the comprehensive API specification on SwaggerHub as well as in OpenAPI v3 format (OpenAPI v3 specification itself).
API Specification on SwaggerHub API Specification in OpenAPI v3 format
Authentication
For API authentication, it's necessary to generate an organization API key beforehand. Keys can be managed in Billberry on the organization page, which you can find under account and settings.
After generating a new API key, you'll be shown the key identifier and password. For example:
Id | 42 |
---|---|
Key | 2ab96390c7dbe3439de74d0c9b0b1767 |
You can later identify the key based on the identifier if you wish to occasionally exchange old keys for new ones. API keys are 16-byte random numbers (displayed in hex format), so if desired, you can also store them in the database in binary format (BLOB
).
HTTP request authentication is done with the Authorization
header and Basic authentication. The username shall be the API key identifier, and the password the key itself. For example, with the sample key above, the HTTP request should look like this:
GET /invoices/received HTTP/1.1
Host: api.billberry.ee
Authorization: Basic NDI6MmFiOTYzOTBjN2RiZTM0MzlkZTc0ZDBjOWIwYjE3Njc=
Accept: application/vnd.billberry.invoice+json; v=1
Using cURL, you can provide the API key id and password with the --user
parameter:
curl --user 42:2ab96390c7dbe3439de74d0c9b0b1767 https://api.billberry.ee/…
Versioning
API versioning is handled through the standard Accept
and Content-Type
headers. You can find the MIME types and their schemas for each request in the API specification.
For example, the MIME type for invoice metadata is:
application/vnd.billberry.invoice+json; v=1
Within a single version, documented attributes will never be changed or removed. For JSON responses, it's safe to presume new attributes may be added, but this shouldn't affect interpreting responses. Unknown attributes can simply be ignored when parsing.
Error Handling
Billberry API responds to failed requests with HTTP error codes (status codes in the range of 400–599) and a reason (status message / reason phrase).
Possible error codes and messages are described in the API specification next to each endpoint, but it's worth noting that error messages may be added. While primarily intended for developers, they may be displayed to end-users if necessary — there are no secrets in these messages. In fact, the optional description
property in the error response, is written to be shown to end-users.
For example, when sending an e-invoice to a company that does not accept e-invoices, Billberry responds with an error code 409
and the reason Organization Doesn't Accept E-Invoices
.
POST /invoices HTTP/1.1
Host: api.billberry.ee
Content-Type: application/xml
Accept: application/vnd.billberry.invoice+json; v=1
HTTP/1.1 409 Organization Doesn't Accept E-Invoices
If you add the Billberry error message MIME type application/vnd.billberry.error+json; v=1
to the Accept
header, you can receive the error object in JSON. In this case, the reason is found in the message
attribute after the status line:
POST /invoices HTTP/1.1
Host: api.billberry.ee
Content-Type: application/xml
Accept:
application/vnd.billberry.invoice+json; v=1,
application/vnd.billberry.error+json; v=1
HTTP/1.1 409 Organization Doesn't Accept E-Invoices
Content-Type: application/vnd.billberry.error+json; v=1
{
"message": "Organization Doesn't Accept E-Invoices"
}
Sending and Receiving Invoices
- Invoice Resource
/invoices
- Invoice MIME Type
application/vnd.billberry.invoice+json; v=1
Sending E-invoices
You can send e-invoices conforming to the Estonian e-invoice standard using POST /invoices
.
POST /invoices HTTP/1.1
Host: api.billberry.ee
Content-Type: application/xml
Accept: application/vnd.billberry.invoice+json; v=1
X-Send: immediately
Presently, only synchronous sending is supported (header X-Send: immediately
). This means that the request will not receive a response until the receiving operator has accepted or rejected the invoice. Typically, this takes less than a second. Synchronicity reduces the risk of the e-invoice getting lost should the other operator decide not to accept it later. It also simplifies implementation, as an API client, you don't have to inquire about the status of an invoice later.
There's a maximum timeout of 15 seconds when delivering to other operators. If the receiving operator doesn't respond within this time, you'll receive an error 504 ${Operator} Timeout
, where ${Operator}
denotes the name of the failed operator.
When the e-invoice is correctly formatted and the buyer accepts e-invoices, you'll receive a 201 Sent
response.
HTTP/1.1 201 Sent
Content-Type: application/vnd.billberry.invoice+json; v=1
{
"id": 42,
"type": "debit",
"registryCode": "16122596",
"senderRegistryCode": "16122596",
"senderName": "Seller Company OÜ",
"receiverRegistryCode": "16122597",
"receiverName": "Buyer Company OÜ",
"number": "INV123",
"date": "2020-06-18",
"dueDate": "2020-06-25",
"receivedAt": null,
"receivedFromOperator": null,
"receivedFileId": null,
"receivedExternalId": null,
"sentAt": "2020-06-18T13:37:42.666Z",
"sentToOperator": "billberry",
"sentFileId": "42",
"sentExternalId": "43"
}
You can find a description and schema for all attributes in the API specification including possible error messages. For example, attempting to send an e-invoice to a company that does not accept e-invoices results in a 403 Organization Doesn't Accept E-Invoices
response.
Sending an e-invoice with cURL looks like this, with the XML in the file invoice.xml
:
curl https://api.billberry.ee/invoices \
--user 42:2ab96390c7dbe3439de74d0c9b0b1767 \
--data @invoice.xml \
--header "Accept: application/vnd.billberry.invoice+json; v=1" \
--header "Content-Type: application/xml" \
--header "X-Send: immediately"
Receiving E-invoices
You can fetch the invoices sent to your company with the GET /invoices/received
request.
GET /invoices/received HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.invoice+json; v=1
HTTP/1.1 200 OK
Content-Type: application/vnd.billberry.invoice+json; v=1
Link: </invoices/received?id%3e42>; rel="updates"
[{
"id": 42,
"type": "debit",
"registryCode": "16122597",
"senderRegistryCode": "16122596",
"senderName": "Seller Company OÜ",
"receiverRegistryCode": "16122597",
"receiverName": "Buyer Company OÜ",
"number": "INV123",
"date": "2020-06-18",
"dueDate": "2020-06-25",
"receivedAt": null,
"receivedFromOperator": null,
"receivedFileId": null,
"receivedExternalId": null,
"sentAt": "2020-06-18T13:37:42.666Z",
"sentToOperator": "billberry",
"sentFileId": "42",
"sentExternalId": "43"
}]
You can find a description and schema for all attributes in the API specification.
Synchronization
For synchronizing received invoices, grab the updates
URL from the Link
header. By requesting this endpoint next time, you'll only receive invoices that arrived after the last query.
Link: </invoices/received?id%3e42>; rel="updates"
Based on the previous example, after the first /invoices/received
request, you'll find /invoices/received?id%3e42
in the Link
header. Use this path when querying for invoices next time. If new invoices have arrived in the meantime, only those will be returned. At the end of the request, again, take the new updates
address from the Link
header and set it aside for next time. Each request response points to a new updates
link. Old updates
links will continue to work, so in case of a failed import, you can simply try the same address again. You can always retrieve all received invoices with the original /invoices/received
request.
The format of the Link
header is described in RFC 8288 and in the older RFC 5988.
Why not use timestamps for invoice synchronization as seen in some APIs?
Using timestamps is a risky synchronization method both in theory and practice. Firstly, computer timestamps are not monotonically increasing (including UTC). UTC regularly introduces leap seconds, causing the clock to jump forward or backward by a second. Consequently, a later-received invoice might have an earlier timestamp due to leap seconds. Aside from leap seconds, server clock time is also influenced by time synchronization (NTP). In a situation where the server clock runs ahead or falls behind for some reason, a temporary time shift of a few seconds can occur.
The most dangerous pattern though can be seen on another local Estonian e-invoice operator whose API uses not only timestamps, but also local timestamps (in the style of 2021-06-18 13:37:42
) for synchronization. This implies that on the night of switching to winter time (when the clock is set back by an hour), their API will omit invoices received between after the clock change.
Using Billberry's synchronization (updates
header) links, no invoice is ever missed because they do not rely on timestamps.
Request new invoices at most every 1–5 minutes as unfortunately e-invoices from other operators tend to not arrive more frequently. Some operators take at least 15–30 minutes to forward invoices.
If you want to know about received invoices within a second, Billberry can also offer a Server-Sent Events solution instead of the described polling option. Let us know by email if you're interested.
Received E-invoice XML
You can grab the XML of received invoices in the Estonian e-invoice format with the GET /invoices/{invoiceId}.xml
request.
GET /invoices/{invoiceId}.xml HTTP/1.1
Host: api.billberry.ee
Accept: application/xml
HTTP/1.1 200 OK
Content-Type: application/xml