# Tutorial: Join events (Add Attachment flow)
This page describes the steps necessary to add (an) attachment(s) to invoices.
There are two ways to set up this flow: optional / multiple attachments, and single required attachment.
Luckily, the basics are the same, it just requires a different expression or adding a delay to the hook's action.
# Set up hooks
First of all there should be two hooks generating the events to join. This is covered in the other sections under hooks.
These hooks will result in topics that the join hook can respond to. We will also have to determine how to match these events.
To do this we will use expressions, which will be explained below (but more extensively here under the moniker filters)
# Expressions
The join hook knows two types of events: target events (containing the primary document, i.e. invoice or order) and matching events (attachments). We will use expressions to determine which event is the primary document, and which event should be matched to it and how.
Should you need help setting up these expressions, please contact tech support.
# Target event
Let's assume we'll receive two different event topics: SalesInvoiceReceived and AttachmentReceived.
An example of an expression to determine whether an incoming event is the primary document would look like
topic=="SalesInvoiceReceived"
.
This matches the current event topic with the given expression. We call this the join target
expression.
All expressions should be URL-escaped, which means the above expression will look like topic%3D%3D%22SalesInvoiceReceived%22
.
# Matching event
Building on the example above, we will need to find a matching event (or multiple events - more on that later).
We should be able to identify the id for the primary document. If the attachment is sent with additional information containing the same id, we can match these in the join when
expression.
An example expression would look like target.id==source.id && target.sender==source.sender
.
All events will be matched with this event to determine a match. The current event will be named source
, and the undetermined event target
.
In this case we are comparing the target id (invoice id) with the source id (invoice id passed to hook), as well as making sure they are intended for the same party.
All expressions should be URL-escaped, which means the above expression will look like target.id%20%3D%3D%20source.id%20%26%26%20target.sender%20%3D%3D%20source.sender
.
# Hook action
The action should be formatted like: "action":"join://AddAttachment?target={target}&when={when}&ttl={ttl}&delay={delay}"
.
Note that there are additional (optional) parameters here: ttl
and delay
.
If ttl is left out, a default value of one day is used.
The ttl
sets the 'wait' time before we throw a *JoinedError
after the set time. This can be used to detect missing sets of target & matching events (i.e. one of the invoices has not been supplied, but the attachment has been supplied).
If delay is left out, none is used.
The delay
is to be used when joining multiple matching events for a single target event. When the target event is detected (and the delay is set), the delay
time is waited until all events are checked for matching.
All supplied matching events will be joined together and all attachments will be added to the target document.
The example config would look like this:
{
"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
}