Skip to content
iQBus HomeDocumentationBlogContact
Updated September 18, 2026
Tutorials/File & batch patterns/Partner document relay

Partner document relay

A shipping carrier and a customs broker both work with Acme, and the carrier keeps producing dispatch documents, one per shipment, that the broker needs to clear goods. Nobody pushes them across. Instead Acme checks the carrier’s server every few minutes, picks up whatever is new, and delivers each document to the broker. At the same time Acme keeps its own copy of every document in a safe folder, so months later, if anyone asks "did you really send that one?", the answer is on file. The documents are passed along exactly as they arrive, nothing is changed. If the broker’s server is down, the file is set aside and delivered later, and the safe copy is still made either way.

So there are three parties and a clock. The carrier leaves documents in a pickup folder. A timer wakes up on a schedule, collects the new ones, hands each to the broker, and tucks a copy into the archive. The job is plain courier work, move the file, keep a receipt, and never lose track of what was sent.

Pick up each document, deliver it, keep a copy Carrier folder new dispatch docs every few min Pick up what is new Deliver to broker waits and retries if down Save a copy in the archive the receipt, made every time

You could write a script that does this, download, upload, delete, and it would work right up until the broker’s server is down at 03:00 and nobody can say which files made it across. iQBus does the same courier work but puts it on the bus, the shared message backbone every flow publishes to and subscribes from, and that is what buys the retries, the audit trail, and the ability to send a document again on request. Here is how it is built.

The pickup leg mirrors the scheduled pickup. An SFTP Listener receive port (a receive port is the entry point that brings work onto the bus, and an adapter is the connector for one kind of system, here a file server reached over SFTP) polls the carrier every 15 minutes and which downloads whatever is new in the carrier’s outbound directory. Each fetched document re-enters the bus as a DispatchDocument, a message type, which is just a name plus a format that lets subscriptions recognise the document, body untouched. Outbound filenames are derived from the payload itself: the document number is the one identifier that survives the trip, so both legs name the file the same way without any shared state.

Two send ports then subscribe to the same type, the delivery and the archive, the same move as the order fan-out. A subscription is just a rule that says which messages a port wants:

EXPRESSION
{{Message.MessageType}} == "DispatchDocument"
TEMPLATE
Path : /archive/dispatch/dispatch_{{Promoted.DispatchDocument.DocumentNo}}.xml
Carrier SFTPoutbound dir pick up SFTP Listener every 15 min, deletes BUS SFTP Caller, broker one file per doc SFTP Caller, archive /archive/dispatch/ Broker

A naive script doing the same job, download, upload, delete, works until the broker's server is down at 03:00, and then nobody can say which files made it across. Here the archive subscription is the flight recorder: every document that entered the relay is on disk under its document number, whatever happened on the delivery leg, and a dispute is settled by replaying the archived run, design for replay.

When it fails. Three ports, one shared exception type, RelayFailed, and one O365 Mail operations subscription; tracking shows which port raised it. The legs are independent, a broker outage suspends deliveries while fetching and archiving continue, and the backlog drains through retries or replay when the server returns. Treat an archive failure as seriously as a delivery failure: an audit trail with holes is the kind that fails its first real test.

EXPRESSION
{{Message.MessageType}} == "RelayFailed"
Don't re-fetch what you already relayed. The carrier's directory is the source of "what's new", track processed filenames (move them aside on the server if the carrier allows, or keep a processed-list the fetch checks) so an overlapping poll doesn't relay the same document twice. If a duplicate does slip through, the broker delivery should be idempotent on the document number, which is also the outbound filename.

Build it, step by step. The steps run in dependency order: every object is created before the object that selects it.

Before you start. Everything below lives inside one Application. Under Applications, create AcmeLogistics with Namespace AcmeLogistics and select it, so every port and message type below is created in its scope.
1
Step One
Create the message types
The two types

Under the application’s Message types, create the two types this flow routes on. A message type is a name plus a format, no schema required:

NameFormatPurpose
DispatchDocumentXMLthe carrier’s document, relayed body-untouched
RelayFailedXMLthe exception type the failure path publishes under (Step 6)

Promotions live on the message type, so add them while you are here. Both delivery filenames (Steps 5 and 6) and the alert subject (Step 6) bind these tokens, and adapter parameters are plain strings: they take promotions, never body paths.

Promotion on DispatchDocument
PromotionPath
DocumentNo/DispatchAdvice/DocumentNo
Promotion on RelayFailed

A failed relay re-publishes the document payload intact, but promotions are type-qualified, so the exception type needs its own:

PromotionPath
DocumentNo/DispatchAdvice/DocumentNo

2
Step Two
Create the Authentications

Four remote systems, four credentials. Under the application’s Authentications, the dialog asks for a Name, the Adapter it pairs with, and a Definition, the credential shape that adapter offers, with the Application preset; the Definition decides the config section that follows.

Carrier server, for the pickup port
SettingValue
NameCarrierSftp
AdapterSFTP Listener
DefinitionSFTP Password Authentication
Username / Passwordthe carrier’s SFTP login
Host Key Fingerprintthe carrier server’s fingerprint
Broker server, for the delivery port
SettingValue
NameBrokerSftp
AdapterSFTP Caller
DefinitionSFTP Password Authentication
Username / Passwordthe broker’s SFTP login
Host Key Fingerprintthe broker server’s fingerprint
Archive server, for the archive port
SettingValue
NameArchiveSftp
AdapterSFTP Caller
DefinitionSFTP Password Authentication
Username / Passwordyour archive server’s SFTP login
Host Key Fingerprintthe archive server’s fingerprint
Alert mailbox, for O365 Mail
SettingValue
NameO365Ops
AdapterO365 Mail Sender
DefinitionMicrosoft Graph
Tenant Id / Client Id / Client Secret (Graph AuthConfig)an app registration with Mail.Send granted

3
Step Three
Create the pickup port
General

Create an SFTP Listener receive port CarrierPickup against the carrier’s outbound directory. One port does the whole intake: it owns the timing, makes the connection, and publishes what it finds, so there is no clock port and no subscription to wire up. (The dropdowns can also create types and maps inline; building the dependencies first keeps each dialog a selection.)

SettingValue
AdapterSFTP Listener
WayOne
Auth Config TypeStatic
Auth ConfigCarrierSftp, from Step 2
Hostsftp.carrier.example
Port22
Polling Interval (seconds)900; fifteen minutes, the cadence the relay used to get from its clock
Max Files Per Poll20; a busy carrier can drop several dispatch documents between polls
Max Batch Size in Bytes10485760
Path/outbound/dispatch
File Mask*.xml
Include SubfoldersOff
Type the file at the adapter

The port carries a required Adapter Message Type, stamped the instant the Listener releases the file to the next step inside the port, body untouched.

SettingValue
Adapter Message TypeDispatchDocument, from Step 1
The pickup deletes the carrier’s file, and there is no setting to stop it. That solves the duplicate problem this relay used to have to solve by hand: a file is picked up exactly once because it is gone afterwards. It also means the carrier’s copy is gone. If a relay run fails you replay it from Tracking, which still holds the document as it arrived; you do not go back to the carrier for it. Point the Listener at a directory the carrier publishes into, never one they also read from.

A sample dispatch document as the carrier publishes it:

XML
<DispatchAdvice>
  <DocumentNo>CMR-55812</DocumentNo>
  <Carrier>NordFreight</Carrier>
  <Consignee>Beltrans Customs BV</Consignee>
  <Packages>14</Packages>
</DispatchAdvice>

4
Step Four
Create the broker delivery port
General

Create an SFTP Caller send port BrokerDelivery subscribing on {{Message.MessageType}} == "DispatchDocument".

SettingValue
AdapterSFTP Caller
WayOne
Auth Config TypeStatic
Auth ConfigBrokerSftp, from Step 2
Hostthe broker’s server
Port22
Paththeir inbound directory plus the file name, e.g. /inbound/dispatch_{{Promoted.DispatchDocument.DocumentNo}}.xml
OverwriteOff; a repeat of the same document number fails rather than replacing one the broker may already have collected
Create Directory If Not ExistsOff; the broker’s inbound directory is theirs and it exists
Request Payload ModeText; the dispatch document is XML
Pair the credential

Set Authentication to BrokerSftp, from Step 2.

Set the filename

The Filename is rebuilt from the Step 1 DocumentNo Promotion, so the broker copy and the archive copy (Step 5) always match, and a replayed document overwrites nothing at the broker (Fail if exists surfaces the duplicate instead):

EXPRESSION
BrokerDelivery : dispatch_{{Promoted.DispatchDocument.DocumentNo}}.xml
Archive        : dispatch_{{Promoted.DispatchDocument.DocumentNo}}.xml

5
Step Five
Create the archive port
General

Create a second SFTP Caller send port Archive on the same subscription, {{Message.MessageType}} == "DispatchDocument", with the same payload-derived Filename template as Step 4.

SettingValue
AdapterSFTP Caller
WayOne
Auth Config TypeStatic
Auth ConfigArchiveSftp, from Step 2
Hostyour archive server
Port22
Path/archive/dispatch/dispatch_{{Promoted.DispatchDocument.DocumentNo}}.xml
OverwriteOff; the archive keeps one copy per document number
Create Directory If Not ExistsOn
Request Payload ModeText
Pair the credential

Set Authentication to ArchiveSftp, from Step 2.


6
Step Six
Wire the failure path
Set the Exception Message Type

On the pickup port CarrierPickup and both send ports, BrokerDelivery and Archive, set Exception Message Type to RelayFailed, from Step 1; the promotion you defined on it carries the document number into the alert subject.

Create the OpsAlert send port

Create the OpsAlert O365 Mail port subscribing on {{Message.MessageType}} == "RelayFailed":

SettingValue
AuthenticationO365Ops, from Step 2
Fromnoreply@acme.example
Toops@acme.example
SubjectRelay failed: {{Promoted.RelayFailed.DocumentNo}}

7
Step Seven
Start the ports and test
Start in dependency order

Everything you configure is live the moment you save it, there is nothing to deploy. Start the send ports first, BrokerDelivery, Archive and OpsAlert, then the receive port CarrierPickup.

Turn on tracking

Set the Application’s tracking level to Enabled + Body so you can walk each run step by step, with its message body. Tracking is an Application-level setting, so this one choice covers every port the flow touches, and you can drop it back to Only on Error once the flow is proven.

Drop a test document

Drop a test document on the carrier server, and confirm it appears on the broker server and under the archive path.

Break it on purpose

Stop the broker server, drop another document: the archive copy still lands, the delivery suspends and alerts, and replay drains it later. That asymmetry, flight recorder intact while a leg is down, is the test that matters.