Receiving inbound messages

Get notified when an inbound message is ready, fetch its documents, and confirm that your system has stored them.

When Unimaze receives a message for your participant, for example an invoice from a supplier, it validates the message and holds it for your system. Your system then does three things:

  1. Gets notified that the message is ready, through a webhook.
  2. Fetches the documents, as JSON or in their own format.
  3. Confirms the outcome, so the message is no longer pending.

Webhooks are the recommended way to learn about new messages. Polling is the legacy way, described in Polling (legacy) at the end of this page.

sequenceDiagram
    participant U as Unimaze
    participant W as Your webhook endpoint
    participant E as Your back-end (ERP)

    U->>W: POST deliveryNotified (inbound, signed)
    W-->>U: 204 No Content (within 5 seconds)
    W->>E: Queue for processing
    E->>U: Fetch the document (XML or JSON)
    U-->>E: Invoice
    E->>E: Store the invoice
    E->>U: POST /api/v1/messages/{messageId}/mark-as-delivered

All paths on this page are relative to your environment's base URL, for example https://mapi-sandbox.unimaze.com for the sandbox.

1. Get notified

Set up a webhook endpoint that receives the Inbound messages event category. When a message is validated and all its documents are stored, its status is pendingdelivery, and Unimaze sends your endpoint a deliveryNotified event with transfer set to inbound.

Verify the signature, store or queue the event, and respond with 2xx within 5 seconds. Fetch and import the documents in the background.

The event names the message in messageId. Its data is the message envelope, the same object that GET /api/v1/messages/{messageId} returns. A shortened example:

{
  "eventId": "7d1f3a52-0c4e-4b8e-9a6d-2f1e5b7c9a10",
  "action": "deliveryNotified",
  "transfer": "inbound",
  "occurredAt": "2026-10-02T09:15:04.120Z",
  "test": false,
  "party": "0196:5504030000",
  "messageId": "6cfa5c24-25c5-4eb4-bed5-3ed6cc6c25c5",
  "data": {
    "uniqueId": "6cfa5c24-25c5-4eb4-bed5-3ed6cc6c25c5",
    "timeReceived": "2026-10-02T09:15:02.870Z",
    "documentNo": "INV-2026-0187",
    "status": "pendingdelivery",
    "transfer": "inbound",
    "taxReportingStatus": "none",
    "lifecycleStatus": "none",
    "action": "SubmitInvoice",
    "originParty": { "identifier": "0196:6511230889", "name": "Example Supplier ehf.", "countryCode": "IS" },
    "destinationParty": { "identifier": "0196:5504030000", "name": "Example Buyer hf.", "countryCode": "IS" },
    "documents": [
      {
        "index": 0, "name": "Invoice", "contentType": "application/xml", "attachmentType": "Core", "isTransformed": false,
        "transaction": {
          "transactionKeyName": "BISENUBL-3.0 SubmitInvoice",
          "profileIdentifier": "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0",
          "customizationIdentifier": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0",
          "documentIdentifier": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"
        }
      },
      { "index": 1, "name": "INV-2026-0187.pdf", "contentType": "application/pdf", "attachmentType": "Embedded", "isTransformed": false }
    ]
  }
}

data.action names the business transaction, for example SubmitInvoice or CorrectWithCredit. Use it to choose the fetch call in the next step.

2. Fetch the documents

To import structured data, fetch the document as JSON with the call for its transaction:

The JSON is the same whatever document specification the sender used, so your import doesn't depend on your business partners' formats.

To get a document in its own format, such as the UBL XML or a PDF attachment, use the documents calls:

If Unimaze transformed the core document into a specification your system can process, /documents/transformed returns the transformed document, and /documents/original returns it as the sender sent it.

If you import the JSON from the transaction calls above, data.action (for example SubmitInvoice) is all you need to know what you get. If you parse a document in its own format, read its transaction in data.documents to know which standard it follows: the profile, customization and document type identifiers. It is set on the Core document and, after a transformation, on the Original document. The Original document has the transaction the sender used, and the transformed Core document the one it was transformed to.

3. Confirm the outcome

Responding 2xx to the webhook never changes the message. When your system has safely stored the message, confirm it with one of these calls:

  • Both calls work while the message is pendingdelivery, and mark-as-failed also while it is pendingprocessing. In any other status they return 422.
  • errorMessage is required. Say why the import failed, so the problem can be fixed.
  • delivered and failed are final: the message changes again only if someone retries it manually.
  • Your change also sends a messageStatusChanged event, unless that is switched off for the routing rule.

Daily safety-net check

Each notification is sent once, and retried only if your endpoint doesn't respond. If your endpoint accepted a webhook but the message was never confirmed, for example because your system stopped, the message stays pendingdelivery.

Once a day, list these messages with GET /api/v1/messages?status=pendingdelivery&transfer=inbound, and fetch and confirm each one as in steps 2 and 3.

Special cases

  • Replies to messages you sent. Message level responses (MLRs and eMLRs) arrive as inbound messages. They wait in pendingdelivery like any other message: fetch them with /documents/core and mark them as delivered. See Working with MLRs, eMLRs and MLAs.
  • A processing step before import. If your participant has a processing step, for example an approval system, a new message first waits in pendingprocessing, and the processing system gets a processingNotified event in the Inbound processing notifications category. When the processing system calls POST /api/v1/messages/{messageId}/mark-as-processed, the message becomes pendingdelivery and deliveryNotified is sent. Until then, your ERP knows about the message only from its created event: note the messageId, and import the documents on deliveryNotified. See Processing step.
  • Import queue. If your participant has an import queue, messages waiting to be imported are announced with importNotified and confirmed with mark-as-imported. See Pending import messages.

Polling (legacy)

Polling is supported for existing integrations; new integrations should use webhooks.

To poll, call GET /api/v1/messages?status=pendingdelivery&transfer=inbound on a schedule. By default it returns the 50 most recent pending messages; use offset and limit to page through more. Then fetch and confirm each message as in steps 2 and 3.

To move from polling to webhooks, see Polling (legacy).


Did this page help you?