Over SFTP
Drop a file to send it, collect files that arrive.
If your system already writes invoice files, this is the shorter path: no HTTP client, no key handling in your code. You connect over SFTP, put a file in out/, and it goes. Documents addressed to you appear in in/.
Connecting
You were given a username and either a password or a public key — whichever was set up for your login. Ask for the host, port and host key fingerprint before you connect, and pin the fingerprint in your client.
The fingerprint matters. It is what proves you are talking to us and not to something that answered instead, and it does not change. A client that accepts any host key will connect happily to an impostor.
sftp -P 22 kinnefrukt@ftp.businessgateway.seWhat you see
in/ documents that arrived for you
out/ put documents here to send them
out/sent/ what went out successfully
out/failed/ what did not, each with a .error.json beside itYou may write into out/ and read from in/; that is the whole permitted surface. It is not a general file system, and anything else is refused.
If your login covers more than one company, or was set up per Peppol address, you will step through one or two directories named after the company or the address before reaching in/ and out/. What your login sees is fixed when it is created.
Sending
Copy the XML into out/. That is all.
We read the sender, the receiver and the document type out of the document itself, so an ordinary Peppol invoice needs nothing alongside it. When that is not possible — the document does not name a single recipient, or its type cannot be recognised — put a JSON file with the same base name next to it:
{
"sender": "0007:5561234567",
"receiver": "0007:5569876543",
"type": "invoice"
}invoice.xml pairs with invoice.json. The sidecar is not itself treated as a document.
Once the file has been picked up it moves out of out/:
- Sent →
out/sent/, keeping its name, so you can find it again. - Failed →
out/failed/, with<name>.error.jsonbeside it saying why. Read that file before resending; a validation failure will fail again unchanged.
Uploading safely
Do not leave half-written files where we can see them. Files whose names end in .tmp, .part or .filepart, and files whose names begin with a dot, are ignored — so the reliable pattern is to upload as invoice.xml.part and rename to invoice.xml when the transfer is complete. Most SFTP clients can be told to do exactly this.
Sending the same file twice under the same name for the same address is recognised as a repeat and will not produce two documents.
Receiving
Documents that arrive for you appear in in/, named {documentId}.xml unless a different pattern was configured for your account. Depending on setup they may be organised into date directories — in/2026/09/12/ — and each may come with a small JSON file describing it.
Collect them on whatever schedule suits you. They are not deleted because you have not collected them yet.
If you want to know the moment something lands rather than waiting for your next poll, add a webhook — it works alongside SFTP.
If something does not move
| Symptom | Look at |
|---|---|
The file sits in out/ | Is it still named .part or .tmp? Is it in the right directory for the company? |
It landed in out/failed/ | The .error.json beside it |
Nothing ever arrives in in/ | Your trading partner may be sending to the wrong address, or you may not be registered to receive that document type |
| The connection is refused | Wrong host key pinned, disabled login, or a source address that is not allowed |
Your login can be restricted to particular source addresses, and repeated failed attempts lock it temporarily. If you have changed office network, that is the first thing to check.