Join hooks: merging attachments with documents

Merge attachments with documents via join hooks: target and when expressions, TTL and delay.

Sometimes the parts of a document come from different sources. Think of an XML invoice arriving via Peppol and a PDF attachment delivered separately, or multiple attachments belonging to the same invoice. With a join hook the PSB automatically combines these separate events into a single document.

How does a join hook work?

A join hook listens on multiple topics simultaneously and recognises which events belong together. The hook distinguishes two types of events:

  • Target events: the primary document (for example an invoice or order).
  • Matching events: attachments or supplements that need to be linked to the primary document.

Using expressions you determine which event is the primary document (target) and how attachments are matched (when). As soon as the PSB finds a match, it merges the attachments with the primary document and publishes a new topic.

The flow is as follows:

  1. The PSB receives events on the configured topics (for example SalesInvoiceReceived and AttachmentReceived)
  2. The join hook evaluates each event against the target expression to identify the primary document
  3. With each new event the hook checks the when expression to find a match
  4. Once target and matching event(s) are linked, the PSB adds the attachments to the primary document
  5. A new topic is published (for example SalesInvoiceJoined)
Configuring expressions

The power of join hooks lies in the expressions. You write two expressions: one for identifying the primary document and one for matching attachments.

Target expression

The target expression determines whether an event is the primary document. A commonly used pattern is matching on the topic:

topic=="SalesInvoiceReceived"
When expression

The when expression links a matching event to the correct target event. Here you compare fields between the source event (source) and the target event (target):

target.id == source.id && target.sender == source.sender

In this example events are matched if they have the same document ID and the same sender.

Note: all expressions must be URL-encoded in the action URL. The expression topic=="SalesInvoiceReceived" becomes topic%3D%3D%22SalesInvoiceReceived%22. Do not forget this, as the PSB parses the expressions from the query string.

Creating a join hook

Register a hook via the API with a join://AddAttachment action:

{
  "id": "1",
  "name": "join hook",
  "action": "join://AddAttachment?target=topic%3D%3D%22SalesInvoiceReceived%22&when=target.id%20%3D%3D%20source.id%20%26%26%20target.sender%20%3D%3D%20source.sender&ttl=00:15:00&delay=00:30:00",
  "topics": [
    "AttachmentReceived",
    "SalesInvoiceReceived"
  ],
  "publishTopics": [
    "SalesInvoiceJoined"
  ],
  "isActive": true
}

The action follows the format:

join://AddAttachment?target={target-expression}&when={when-expression}&ttl={ttl}&delay={delay}
Parameters
ParameterRequiredDefaultDescriptiontargetYesURL-encoded expression that determines whether an event is the primary documentwhenYesURL-encoded expression that links matching events to the target eventttlNo1.00:00:00 (1 day)Maximum wait time for a match. After this time the PSB publishes a *JoinedError topicdelayNononeWait time after detection of the target event, allowing multiple attachments to arrive before the merge starts
Configuring topics

The topics array of the hook must contain all topics the join hook should listen on. This includes topics for both the primary document and the attachments.

The publishTopics field determines on which topic the merged document is published. You can configure a regular webhook or e-mail hook on this topic to receive the result.

TTL: wait time and error detection

The ttl (Time to Live) determines how long the PSB waits for a match. If after the TTL period the primary document or attachment is missing, the PSB publishes an error topic (*JoinedError). This lets you detect when a set is incomplete.

Set the TTL to a value that matches your expected turnaround time. If attachments typically arrive within one hour, a TTL of 01:00:00 is sufficient.

Tip: configure a webhook or e-mail hook on the *JoinedError topic. This gives you a signal when an attachment or invoice is missing, allowing you to take timely action.

Delay: merging multiple attachments

Without a delay the merge starts as soon as the target event and one matching event are found. If you expect multiple attachments for the same document, set a delay. The PSB waits the specified time after detecting the target event and then merges all attachments matched during that period in one go.

Suppose you expect three PDF attachments for an invoice and they arrive over a period of 20 minutes. A delay of 00:30:00 provides enough margin to collect all attachments.

Practical example

An organisation receives invoices via Peppol (topic SalesInvoiceReceived) and accompanying PDF attachments via a separate channel (topic AttachmentReceived). The attachments are matched on document ID and sender. After merging, the complete document is published on SalesInvoiceJoined, after which a webhook forwards it to the ERP system.

Frequently asked questions
Why must target and when expressions be URL-encoded in the action?

The PSB reads the expressions from the query string of the join://AddAttachment URL. Special characters such as =, ", spaces and && break the parsing if you do not encode them, for example topic%3D%3D%22SalesInvoiceReceived%22 instead of the raw notation.

What happens if no complete match is found within the ttl?

The ttl (Time to Live) is the maximum waiting time for a valid combination of target and matching events. If the time expires without a match, the PSB publishes a *JoinedError topic, so you can signal that a set is incomplete and take timely action.

When should I set a delay alongside a ttl?

Use delay when you expect multiple attachments to arrive shortly after each other: after detecting the target event, the PSB waits out the delay and then merges all attachments matched during that period in one go. Without a delay, the merge starts as soon as one matching event is found.


Need help setting up the right expressions? Contact TechSupport at [email protected]. See the full API specification at psb.econnect.eu for all configuration options.

View the API documentation