Webhooks
Maventa supports registering webhooks that allow your system to receive real-time notifications about important events. Instead of polling the API for updates, you simply create a webhook subscription using the AX API. Whenever one of the subscribed events occurs, for example, when a new invoice arrives or its status changes, Maventa sends an HTTP POST request to the endpoint you have defined. These incoming POST requests are what we refer to as receiving events. This makes your integration more efficient, faster, and easier to scale.
Registering to receive events via webhooks
You can register webhook subscriptions using POST /v1/company/notifications.
Event names are not validated when you register a subscription. A misspelt name is accepted but never matches an event, so check the names against the event types. You can use * as a wildcard, for example DOCUMENTS.INVOICE.*.
For a single company
If you authenticate as an individual company, you can register a webhook that receives events only for that company.
| Key | Type | Description |
|---|---|---|
| destination_type | string | WEBHOOK |
| destination | string | HTTPS endpoint URL |
Example registering for DELIVERED, DELIVERY_CONFIRMED and FAILED events for invoices
{
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.DELIVERED",
"DOCUMENTS.INVOICE.DELIVERY_CONFIRMED",
"DOCUMENTS.INVOICE.FAILED"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.DELIVERED",
"DOCUMENTS.INVOICE.DELIVERY_CONFIRMED",
"DOCUMENTS.INVOICE.FAILED"
]
}Example registering for all networks and all event types
{
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"NETWORKS.*"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"NETWORKS.*"
]
}Example registering for RECEIVED events for invoices
{
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.RECEIVED"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.RECEIVED"
]
}For all companies linked to a partner (vendor webhooks)
Partners can register webhooks that automatically apply to all companies linked to the partner’s vendor API key. This is a one-time setup. Once the subscription is active, your webhook endpoint receives events for every company associated with that vendor key.
Linking and unlinking vendor API keys is required for this feature to work.
To register vendor webhooks, authenticate with the partner company’s credentials and set destination_type to VENDOR_WEBHOOK.
| Key | Type | Description |
|---|---|---|
| destination_type | string | VENDOR_WEBHOOK |
| destination | string | HTTPS endpoint URL |
Example registering for all events for all document types
{
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.*.*"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.*.*"
]
}Vendor key specific webhooks
If you manage multiple vendor API keys and want events separated per key, include vendor_key in the subscription payload to filter which events you receive.
| Key | Type | Description |
|---|---|---|
| destination_type | string | VENDOR_WEBHOOK |
| destination | string | Endpoint url |
| vendor_key | string | your_vendor_key |
Notifications are scoped to the company (account), not to an individual vendor or user. The vendor_key filter only checks whether the company is linked to the given vendor key — it does not identify which vendor actually triggered the event, because that information is not carried on the event. As a result, when a company is shared by multiple vendors or users, everyone subscribed will see each other’s activity. If you need per-vendor or per-user separation, apply your own filtering on the receiving side.
Example registering for DELIVERED, DELIVERY_CONFIRMED and FAILED events for invoices with vendor webhooks:
{
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"vendor_key": "your_vendor_api_key_here",
"events": [
"DOCUMENTS.INVOICE.DELIVERED",
"DOCUMENTS.INVOICE.DELIVERY_CONFIRMED",
"DOCUMENTS.INVOICE.FAILED"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.DELIVERED",
"DOCUMENTS.INVOICE.DELIVERY_CONFIRMED",
"DOCUMENTS.INVOICE.FAILED"
]
}Example registering for RECEIVED events for invoices with vendor webhooks
{
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"vendor_key": "your_vendor_api_key_here",
"events": [
"DOCUMENTS.INVOICE.RECEIVED"
]
}{
"id": "d726d240-4631-483e-a4e3-61bbefa0e7b7",
"destination_type": "VENDOR_WEBHOOK",
"destination": "https://your.example/endpoint",
"events": [
"DOCUMENTS.INVOICE.RECEIVED"
]
}Handling webhook events
Webhook events are delivered as HTTP POST requests to the endpoint URL (destination) configured during registration. Your webhook endpoint should remain lightweight and respond quickly, handling only minimal processing.
For example, when receiving a DOCUMENTS.INVOICE.RECEIVED event, you should store the event_data and trigger a background process to download the invoice instead of performing heavy or long-running logic in the webhook handler. Maventa waits up to 5 seconds for the connection to open and up to 10 seconds for your response. Requests that time out are treated as failures and will be retried.
Maventa webhooks use an at-least-once delivery model. This means the same event may be delivered multiple times, and your system must handle deduplication to prevent duplicate processing of invoice events. A redelivered event is identical to the original, so you can recognise duplicates by comparing the event, event_timestamp and the document ID in event_data (for example invoice_id). A webhook delivery is considered successful if the endpoint responds with any HTTP 2xx status code. Any other response, a connection error or a timeout is treated as a failure and will trigger a retry. Failed deliveries are retried once per hour, up to 24 times after the first attempt (25 attempts in total, over about 24 hours).
Because webhooks are not guaranteed to be 100% reliable, you should implement safeguards to ensure no events are missed. This can be done by subscribing to unacknowledged webhook events or by using the REST API as a fallback to poll for missing data.
If deliveries to a webhook subscription keep failing for more than 30 days, Maventa deletes the subscription. The 30-day period starts when an event first fails after all retries, and it resets whenever a delivery to that subscription succeeds. A deleted subscription no longer appears in GET /v1/company/notifications, no notification is sent when it is deleted, and you need to register it again.
{
"event": "<event_name>",
"company_id": "<company-uuid>",
"event_timestamp": "<ISO8601-timestamp>",
"event_data": { }
}The event is the name of the event e.g. DOCUMENTS.INVOICE.RECEIVED.
The event_timestamp is the ISO8601 formatted time when the event was originally created. It does not change when the event is redelivered: automatic retries and events resent with POST /v1/company/notifications_resend_unacknowledged carry the same payload, including the same event_timestamp, as the first delivery attempt. The only exception is the UNACKNOWLEDGED_WEBHOOKS notification, which is created anew each time it is sent and gets a new timestamp.
Redelivering a webhook is different from resending the document itself. If an invoice is resent, for example from the Maventa UI, it goes through delivery again and triggers new events, such as a new DELIVERED or FAILED event. These new events keep the same invoice_id but have a new event_timestamp, so they are not duplicates of the earlier events.
The company_id is the UUID of the company the event concerns: the sending company for DELIVERED, DELIVERY_CONFIRMED and FAILED, and the receiving company for RECEIVED. With company webhooks this is your own company. With vendor webhooks it is the customer company the event concerns, not the partner company that registered the webhook.
The event_data is optional and its structure depends on the name of the event.
Examples of event_data
type DocumentsInvoiceReceived
{
"invoice_id": "string",
"invoice_number": "string",
"origin": "string", // e.g. "PEPPOL", or "INTERNAL" when the sender uses Maventa
"sender_name": "string",
"sender_bid": "string"
}type DocumentsInvoiceDelivered
{
"invoice_id": "string",
"invoice_number": "string",
"destination": "string", // e.g. "PEPPOL", "EMAIL", or "INTERNAL" when the recipient uses Maventa
"recipient_name": "string",
"recipient_bid": "string",
"recipient_eia": "string"
}type DocumentsInvoiceDeliveryConfirmed
{
"invoice_id": "string",
"invoice_number": "string",
"destination": "string", // e.g. "PEPPOL", "EMAIL", or "INTERNAL" when the recipient uses Maventa
"recipient_name": "string",
"recipient_bid": "string",
"recipient_eia": "string"
}type DocumentsInvoiceFailed
{
"invoice_id": "string",
"invoice_number": "string",
"destination": "string", // e.g. "PEPPOL", "EMAIL", or "INTERNAL" when the recipient uses Maventa
"recipient_name": "string",
"recipient_bid": "string",
"recipient_eia": "string",
"error_message": "string"
}Payload examples
Example of a payload when an invoice is delivered:
{
"event":"DOCUMENTS.INVOICE.DELIVERED",
"company_id":"53a4e05d-42f0-4e76-acd6-xxxxxxx",
"event_timestamp":"2019-11-23T12:03:48+02:00",
"event_data": {
"invoice_id":"12f88354-5998-495b-8675-xxxxxxxx",
"invoice_number":"1003",
"destination":"PEPPOL",
"recipient_name":"Recipient",
"recipient_bid":"933646920"
}
}Example of a payload when invoice sending fails:
{
"event":"DOCUMENTS.INVOICE.FAILED",
"company_id":"53a4e05d-42f0-4e76-acd6-xxxxxxxxx",
"event_timestamp":"2019-11-23T12:03:48+02:00",
"event_data": {
"invoice_id":"da01a81d-1995-440c-971b-xxxxxxxxx",
"invoice_number":"1001",
"destination":"PEPPOL",
"recipient_name":"Recipient",
"recipient_bid":"933646920",
"error_message": "Error that happened"
}
}Example of a payload when an invoice is received:
{
"event": "DOCUMENTS.INVOICE.RECEIVED",
"company_id": "53a4e05d-42f0-4e76-acd6-xxxxxxxxx",
"event_timestamp": "2024-11-23T12:03:48+02:00",
"event_data": {
"invoice_id": "c154feee-399b-488e-aecd-xxxxxxxxx",
"invoice_number": "1002",
"origin": "PEPPOL",
"sender_name": "Sender",
"sender_bid": "937729111"
}
}Subscribe to unacknowledged webhooks
To improve reliability and ensure that no webhook events are missed, Maventa strongly recommends subscribing to UNACKNOWLEDGED_WEBHOOKS. This subscription notifies you when webhook deliveries have repeatedly failed and provides a controlled mechanism for recovering those events.
When an unacknowledged webhook notification is received, your system can fetch all failed webhook events in a single call using the API method POST /v1/company/notifications_resend_unacknowledged. This endpoint resends all unacknowledged webhook events for the company. Once an event has been successfully processed, any further retry attempts for that event will stop. If deliveries to a subscription keep failing for more than 30 days, that subscription is deleted. Your company’s other subscriptions are not affected.
To enable this functionality, register to the UNACKNOWLEDGED_WEBHOOKS event using the POST /v1/company/notifications.
Example payload:
{
"destination": "https://example.com/webhooks/unacknowledged_webhooks?token=1234",
"destination_type": "WEBHOOK",
"events": [ "UNACKNOWLEDGED_WEBHOOKS" ]
}The notification itself is delivered as the following payload:
{
"event": "UNACKNOWLEDGED_WEBHOOKS",
"company_id": "string",
"event_timestamp": "string",
"event_data": {}
}Subscribing to unacknowledged webhooks provides proactive visibility into delivery issues. If your system fails to acknowledge webhook events for 24 hours, you will receive a single notification summarizing all unacknowledged events. These notifications are sent once per company per day and can continue for up to one month, helping ensure that delivery failures do not go unnoticed.
Security
To ensure that messages sent to your webhook endpoint originate from Maventa, Maventa recommends adding an authorisation mechanism to the webhook URL.
You can use one of the following approaches:
- HTTP Basic Authentication
Example: https://user:examplesecret@your-erp.com/webhooks
When a webhook URL is registered in this format, Maventa will call https://your-erp.com/webhooks and include the HTTP header Authorization: Basic dGVzdDpzZWNyZXQ=
- Secret as a URL parameter
Example: https://your-erp.com/webhooks?secret=examplesecret
The webhook destination must be a publicly reachable HTTPS URL. Registration is rejected with 400 invalid_parameters if the URL doesn’t use https://, or if the host is localhost, ends in .localhost or .local, or is a loopback, private or link-local IP address.
Please note that the webhook endpoint must support TLS 1.2. Older protocols, including SSLv2, SSLv3, TLS 1.0, and TLS 1.1, are not supported.
IP addresses
Webhook requests are sent from several IP addresses, and these addresses can change without advance notice. Do not rely on an IP allowlist to restrict access to your webhook endpoint, as it may block webhook deliveries without warning. See IP addresses and firewalls.
Limited data in webhook payloads
Webhook payloads are designed to carry as little data as possible. They identify the event and the document it concerns but do not contain the document itself. To access the document or other details, your system must call the Maventa API with valid API keys.
Event types
Maventa supports the following events:
DOCUMENTS.*.DELIVERED
Triggered when a document has been successfully handed over to the selected delivery channel (e.g., Peppol, email, print). DELIVERED indicates that Maventa has completed its part of the transmission, but it does not guarantee that the final recipient received or accepted the document. For example, an email invoice may still fail later if the message bounces due to an invalid address or a full inbox.
You can show this status to your customers, but note that DELIVERED does not always represent final delivery success.
DOCUMENTS.*.DELIVERY_CONFIRMED
The DELIVERY_CONFIRMED status indicates that the delivery channel has successfully acknowledged receipt or completed the delivery. Note that not all delivery routes provide this confirmation. When an invoice receives DELIVERY_CONFIRMED, it is considered fully delivered, and the status will no longer change to FAILED.
DOCUMENTS.*.FAILED
Triggered when a document fails to be delivered due to a final error. This may occur even after a DELIVERED event. The event does include the error details.
DOCUMENTS.*.RECEIVED
Triggered when your company receives an invoice or any document.
NETWORKS.*
Triggered for changes in network registrations, such as for Finnish bank network registration (BANK), opening a scan account (SCAN) or registering your company to receive from Peppol network (PEPPOL). Each event reflects a specific lifecycle action: CREATED, ENABLED, DISABLED, or FAILED. FAILED is sent when a registration can’t be activated because of a problem with the registration data, for example when the participant is already registered with another access point or the identifier is invalid.
For example, when the Finnish bank network connection is successfully opened (might take few days from opening), an event NETWORKS.BANK.ENABLED is triggered.
COMPANIES.AUTHORIZATION.*
When a company’s authorization status changes to either VERIFIED, UNVERIFIED or UNKNOWN.
UNACKNOWLEDGED_WEBHOOKS
Happens when your system experiences issues and fails to respond within 24 hours, the company will receive a single notification encompassing all unacknowledged webhook events. Unacknowledged webhooks are dispatched once per company per day and will continue for up to one month