Billberry Partner API
Through the Billberry partner interface (API), you can send e-invoices on behalf of your clients and download the e-invoices sent to them. The partner interface is primarily designed for accounting software providers who want to offer convenient e-billing to their clients without requiring clients to create a Billberry account or manage API keys themselves.
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 API address
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. As a partner, you'll have access to all your clients' e-invoices with a single API key. You can manage keys on the Billberry partner page, which you will receive a link to when becoming a partner.
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 /partners/{partnerId}/organizations HTTP/1.1
Host: api.billberry.ee
Authorization: Basic NDI6MmFiOTYzOTBjN2RiZTM0MzlkZTc4ZDBjOWIwYjE3Njc=
Accept: application/vnd.billberry.partner-organization+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/...
Since the partner key grants access to both client registration and their invoices, clients should not have access to the partner key. Otherwise, one client can send invoices on behalf of others and download everyone's invoices. If you want to make Billberry API requests from clients' computers (in desktop applications), Billberry can help you generate client-specific API keys.
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 /partners/{partnerId}/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 /partners/{partnerId}/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"
}
Managing Clients
Before you can send e-invoices on behalf of a client, you must register them in Billberry's system. Registration helps Billberry verify the invoice being sent is from your client and also facilitates billing between Billberry and you, the partner.
Before sending e-invoices, it is essential to authenticate the client and verify their representation rights ("know your customer"). Since clients don't create accounts in Billberry themselves, this responsibility falls on the partner. Both physical identity checks and digital e-identity methods are sufficient (ID-cards, etc.). Representation rights can be confirmed using the Estonian e-Business Register. In exceptional cases, a bank transfer from the company's account can also be considered as permission. Access to a company's bank account implies that the accountant has been authorized to act on behalf of the company. By registering a client through the Billberry API, you assert that you've verified their representation right.
- Partner's client resource
/partners/{partnerId}/organizations
- Partner's client MIME type
application/vnd.billberry.partner-organization+json; v=1
Client Registration
You can register a client using PUT /partners/{partnerId}/organizations/{registryCode}
, replacing {partnerId}
with the partner identifier and {registryCode}
with the client's registry code. No content is needed for registering e-invoice sending.
PUT /partners/{partnerId}/organizations/{registryCode} HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.partner-organization+json; v=1
A successful registration response will return the organization JSON along with the registration time.
HTTP/1.1 201 Organization Registered
Content-Type: application/vnd.billberry.partner-organization+json; v=1
{
"registryCode": "16122596",
"createdAt": "2021-06-18T13:37:42.666Z",
"deletedAt": null,
"sendingEnabled": true,
"receivingEnabled": false,
"receivingOperator": null
}
You don't need to worry about making duplicate registration. If the client was already registered, and the sending or receiving status wasn't changed, the response is 200 Organization Up-to-Date
.
To enable e-invoice reciving, you do need to include content in the PUT
request and explicitly activate both sending and receiving.
PUT /partners/{partnerId}/organizations/{registryCode} HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.partner-organization+json; v=1
Content-Type: application/vnd.billberry.partner-organization+json; v=1
{
"sendingEnabled": true,
"receivingEnabled": true
}
After enabling receiving, Billberry registers itself as the e-invoice operator for your client in the Estonian Business Register. This informs other e-invoice operators about where to forward e-invoices addressed to your client. Before the association takes effect in the Business Register, your client must confirm Billberry in the e-Business Register. The confirmation will be reflected in the recipients' registry after midnight.
It's possible your client's organization already receives invoices at Billberry. In that case, you don't need to reconfirm the association in the e-Business Register. You can find the client's operator in the receivingOperator
attribute. If it's already "billberry"
, received invoices will immediately be available to you as a partner.
When registering a client without enabling sending or receiving, you won't be charged for the client, but you can still generate a client-specific API key for them. This allows you to generate the key for the new client's computer, and later enable e-invoicing without having to configure new keys for the client.
List of Clients
You can obtain a list of your registered clients with GET /partners/{partnerId}/organizations
, replacing {partnerId}
with the partner identifier.
GET /partners/{partnerId}/organizations HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.partner-organization+json; v=1
Currently, only active clients are displayed. In the future, additional parameters may be added to query deleted clients.
Removing a Client
If you wish to remove a client from Billberry's system, you can do so with DELETE /partners/{partnerId}/organizations/{registryCode}
, replacing {partnerId}
with the partner identifier.
DELETE /partners/{partnerId}/organizations/{registryCode} HTTP/1.1
Host: api.billberry.ee
HTTP/1.1 204 Organization Unregistered
Removing a client also disables all active API keys associated with that client.
Managing Client API Keys
If you want to allow your clients to make direct requests to Billberry's API — for example, by developing a serverless desktop program — consider generating an organization-specific API key for each client. Do not share the partner's key with clients — doing so would give one client the ability to send invoices and download invoices on behalf of others.
If you're developing server-side software, you don't need client-specific keys.
Please note that when using client-specific API keys, requests should be directed to the Billberry Client API. Technically, everything is identical to the partner API, except that in the case of a client, the addresses do not have the /partner/{partnerId}
prefix. For example, you can list received invoices from /invoices/received
and send through /invoices
.
Why separate addresses for client-specific keys? For the API to always be identical for organization-specific keys, regardless of whether the key was generated by the client (through Billberry's web) or by the partner (via the partner API). This allows the software to support the use case where the client copies the API key from Billberry's web to the application without changes. On the other hand, the partner's key provides access to all the partner's clients' invoices at once and deserves a different address, even if only to avoid potential errors.
- Partner's client key resource
/partners/{partnerId}/organizations/{registryCode}/sessions
- Partner's client key MIME type
application/vnd.billberry.session+json; v=1
Generating Client Keys
After registering a client, you can generate new client-specific API keys with POST /partners/{partnerId}/organizations/{registryCode}/sessions
, replacing {partnerId}
with the partner identifier and {registryCode}
with the client's registration code.
POST /partners/{partnerId}/organizations/{registryCode}/sessions HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.session+json; v=1
The response includes the created session along with the identifier (id
) and password (token
):
HTTP/1.1 201 Session Created
Content-Type: application/vnd.billberry.session+json; v=1
{
"id": 42,
"registryCode": "16122596",
"createdAt": "2020-06-18T13:37:42.666Z",
"token": "2ab96390c7dbe3439de74d0c9b0b1767"
}
The password or token
is displayed only once after key creation. Use the key's identifier and password in the Authorization
header for Basic authentication, just like with the partner API key.
Listing Client Keys
You can retrieve a list of client-specific API keys with GET /partners/{partnerId}/organizations/{registryCode}/sessions
, replacing {partnerId}
with the partner's identifier and {registryCode}
with the client's registry code.
GET /partners/{partnerId}/organizations/{registryCode}/sessions HTTP/1.1
Host: api.billberry.ee
Accept: application/vnd.billberry.session+json; v=1
Currently, only active API keys are displayed. In the future, additional parameters may be added to also query deleted keys.
Deleting Client Keys
You can revoke client-specific API keys with DELETE /partners/{partnerId}/organizations/{registryCode}/sessions/{sessionId}
, replacing {partnerId}
with the partner's identifier, {registryCode}
with the client's registry code, and {sessionId}
with the session identifier.
DELETE /partners/{partnerId}/organizations/{registryCode}/sessions/{sessionId} HTTP/1.1
Host: api.billberry.ee
HTTP/1.1 204 Session Deleted
Sending and Receiving Invoices
Once your clients are registered, you can start sending e-invoices on their behalf.
- Invoices Resource
/partners/{partnerId}/invoices
- Invoices Resource for Client-Specific Keys
/invoices
- Invoices 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 /partners/{partnerId}/invoices
, replacing {partnerId}
with the partner's identifier.
POST /partners/{partnerId}/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.
If the e-invoice is correctly formatted and the buyer accepts e-invoices, you will 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, if you attempt to send an e-invoice before the client is registered, the API will respond with 403 Invoice Not From A Partner's Organization
.
Attribute | Description |
---|---|
sentAt | Time of sending. |
sentToOperator | Id of the receiving operator. |
sentFileId | The sent invoice's <E_Invoice> <FileId> . |
sentExternalId | Receiving operator's returned invoice id. |
Receiving E-Invoices
You can fetch the invoices sent to all of your clients using GET /partners/{partnerId}/invoices/received
, replacing {partnerId}
with the partner's identifier.
GET /partners/{partnerId}/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: </partners/{partnerId}/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. In partner's context, you'll probably use the registryCode
attribute, which describes the organization associated with the invoice. For received invoices, registryCode
is equal to receiverRegistryCode
, and for sent invoices, it's equal to senderRegistryCode
.
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: </partners/{partnerId}/invoices/received?id%3e42>; rel="updates"
Based on the previous example, after the first /partners/{partnerId}/invoices/received
request, you'll find /partners/{partnerId}/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 /partners/{partnerId}/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 synchronizing invoices 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.
Receivecd E-invoice XML
You can grab the XML of received invoices in the Estonian e-invoice format with the GET /partners/{partnerId}/invoices/{invoiceId}.xml
request.
GET /partners/{partnerId}/invoices/{invoiceId}.xml HTTP/1.1
Host: api.billberry.ee
Accept: application/xml
HTTP/1.1 200 OK
Content-Type: application/xml