Transport
We've spent a fair bit of time on EDI syntax - i.e. the documents themselves - but we haven't touched on what you do with them, exactly. They're for exchanging data: but how?
EDI Is Asynchronous
You are accustomed to dealing with APIs: you POST some data to an endpoint, and you either get a 200 OK or a 400-series code like 422 Unprocessable Entity when you've done something wrong. Most APIs you've worked with are synchronous: you know what happened at the moment you sent the data.
EDI, however, is asynchronous, generally speaking (I'll add some nuance to this shortly). Instead of calling APIs, you send and receive documents. Conceptually, it is much more like sending and receiving email than it is like working with an API.
In the world of EDI, you can send and receive EDI via multiple protocols. Let's start with SFTP.
SFTP
SSH File Transfer Protocol, also known as Secure File Transfer Protocol (), is an extension of the Secure Shell (SSH) protocol. It was created as a more secure replacement for File Transfer Protocol () and works in much the same way. It has excellent support in the standard libraries of most modern programming languages.
It is commonly used in EDI, especially in non-retail contexts. In most situations, you will be asked to connect to a SFTP server, although you may also be asked to host the server yourself. Typically, you will be given SFTP credentials and the names of two folders, one for inbound EDI and the other for outbound EDI.
This can be quite confusing: when you send a trading partner a document, should you upload it to the "inbound" folder (because it's their inbound document), or to the "outbound" folder (because it's your outbound document)?
The answer is, it depends on the trading partner! Sometimes the only way to tell is when you get to the testing phase and they say they've put a document on the server for you to fetch: if it's in "outbound", well, now you know which folder they're going to use. This can lead to configuration entries in your system like:
in: "Outbound"
out: "Inbound"
Some trading partners recognize this as a source of confusion and have
designed better-named alternatives: Ryder, for instance, uses
toRyder and fromRyder, which
are completely clear!
Authentication
Authentication is typically handled with a username and password, but in some cases, key-based authentication is used. Sometimes, you'll be asked to support password and key-based authentication at the same time.
Firewalls
Most trading partners that use SFTP for EDI maintain a firewall on their SFTP server and will ask you for your IP so they can whitelist it. In cloud-based environments, where your system is deployed to virtual private servers, containers, etc., this can be problematic, because the outbound IP will change. You will need to ensure that your outbound IPs are static, for instance by using a NAT gateway.
Uploading And Downloading Files
To send EDI to an SFTP-based trading partner, you connect to their SFTP
server and upload a proper-formatted EDI document to the folder they
have designated for that purpose (as mentioned above, this might be
labelled inbound or outbound
or something else entirely).
To retrieve EDI, you connect to their SFTP server, iterate through the contents of the folder they have designated for you to fetch EDI documents from, and download anything new. In most cases, you will delete any EDI document that you successfully download to avoid reprocessing it the next time you check for new documents. Some trading partners forbid deletion, however, and instead expect you to move processed documents to an archive folder, or to track which documents you've already retrieved by filename. Typically this is done on a recurring basis, i.e. you regularly poll for new EDI.
The 997
Before we discuss the next communication protocol in the list, we should discuss the , one of a set of documents designed to deal with the problems that arise from the asynchronous nature of EDI.
997 View the 997 transaction set in the X12 ReferenceConceptually, EDI is very similar to email. When you send an email, you generally have little idea what happened to it. You might get a bounceback if you used the wrong email address, but barring that, you don't know if your email was read, deleted or flagged as spam.
EDI has the same problem, but it's magnified. It's one thing when your grandpa's e-card goes into your spam folder, but it's another thing entirely when your customer doesn't receive the advance shipping notification they needed to prepare receipt of a full truckload of goods.
EDI's solution to this problem is the 997, or Functional . The 997 exists to acknowledge successful receipt of an EDI document, or to inform the sender that it was rejected. Note that a 997 reports syntactic acceptance or rejection only: a 997 ACK means your document parsed correctly, not that the partner agreed with its contents. Business-level acceptance is the job of other documents, like the 824 Application Advice.
Here's what a 997 looks like, acknowledging successful receipt of the 990 we worked with earlier in the guide:
FA 997 Functional Acknowledgment - Accepting the 990
EDI
ISA*00* *00* *ZZ*WALDO *ZZ*ACME *250303*1530*U*00401*000000089*0*P*:~ GS*FA*WALDO*ACME*20250303*1530*89*X*004010~ ST*997*0001~ AK1*GF*52~ AK2*990*00000052~ AK5*A~ AK9*A*1*1*1~ SE*6*0001~ GE*1*89~ IEA*1*000000089~
JSON
{
"heading": {
"transaction_set_header_ST": {
"transaction_set_identifier_code_01": "functional_acknowledgment_997",
"transaction_set_control_number_02": "0001"
},
"functional_group_response_header_AK1": {
"functional_identifier_code_01": "response_to_a_load_tender_GF",
"group_control_number_02": "52"
}
},
"detail": {
"transaction_set_response_loop": [
{
"transaction_set_response_header_AK2": {
"transaction_set_identifier_code_01": "response_to_a_load_tender_990",
"transaction_set_control_number_02": "00000052"
},
"transaction_set_response_trailer_AK5": {
"transaction_set_acknowledgment_code_01": "accepted_A"
}
}
],
"functional_group_response_trailer_AK9": {
"functional_group_acknowledge_code_01": "accepted_A",
"number_of_transaction_sets_included_02": 1,
"number_of_received_transaction_sets_03": 1,
"number_of_accepted_transaction_sets_04": 1
}
},
"summary": {
"transaction_set_trailer_SE": {
"number_of_included_segments_01": 6,
"transaction_set_control_number_02": "0001"
}
}
}
Annotated
Interchange Control Header
ISA*00* *00* *ZZ*WALDO *ZZ*ACME *250303*1530*U*00401*000000089*0*P*:~
| Position | Value | Name | Meaning |
|---|---|---|---|
| ISA-05 | ZZ | Interchange ID Qualifier (Sender) | Mutually defined |
| ISA-06 | WALDO | Interchange Sender ID | Waldo Mart is now the sender, since they're acknowledging the 990 |
| ISA-07 | ZZ | Interchange ID Qualifier (Receiver) | Mutually defined |
| ISA-08 | ACME | Interchange Receiver ID | Acme Trucking is now the receiver |
| ISA-09 | 250303 | Interchange Date | |
| ISA-10 | 1530 | Interchange Time | |
| ISA-12 | 00401 | Interchange Control Version Number | X12 release 004010 |
| ISA-13 | 000000089 | Interchange Control Number | |
| ISA-15 | P | Usage Indicator | Production data |
Functional Group Header
GS*FA*WALDO*ACME*20250303*1530*89*X*004010~
| Position | Value | Name | Meaning |
|---|---|---|---|
| GS-01 | FA | Functional Identifier Code | Functional Acknowledgment - identifies this group as containing 997 documents |
| GS-02 | WALDO | Application Sender's Code | |
| GS-03 | ACME | Application Receiver's Code | |
| GS-04 | 20250303 | Date | |
| GS-05 | 1530 | Time | |
| GS-06 | 89 | Group Control Number | |
| GS-07 | X | Responsible Agency Code | Accredited Standards Committee X12 |
| GS-08 | 004010 | Version / Release / Industry Identifier Code |
Transaction Set Header
ST*997*0001~
| Position | Value | Name | Meaning |
|---|---|---|---|
| ST-01 | 997 | Transaction Set Identifier Code | Functional Acknowledgment |
| ST-02 | 0001 | Transaction Set Control Number |
Functional Group Response Header
AK1*GF*52~
| Position | Value | Name | Meaning |
|---|---|---|---|
| AK1-01 | GF | Functional Identifier Code | Response to a Load Tender - this acknowledges a group of 990 transaction sets |
| AK1-02 | 52 | Group Control Number | Echoes GS-06 from the original 990's functional group |
Transaction Set Response Header
AK2*990*00000052~
| Position | Value | Name | Meaning |
|---|---|---|---|
| AK2-01 | 990 | Transaction Set Identifier Code | Response to a Load Tender - identifies the transaction set being acknowledged |
| AK2-02 | 00000052 | Transaction Set Control Number | Echoes ST-02 from the original 990 |
Transaction Set Response Trailer
AK5*A~
| Position | Value | Name | Meaning |
|---|---|---|---|
| AK5-01 | A | Transaction Set Acknowledgment Code | A = Accepted |
Functional Group Response Trailer
AK9*A*1*1*1~
| Position | Value | Name | Meaning |
|---|---|---|---|
| AK9-01 | A | Functional Group Acknowledge Code | A = Accepted |
| AK9-02 | 1 | Number of Transaction Sets Included | |
| AK9-03 | 1 | Number of Received Transaction Sets | |
| AK9-04 | 1 | Number of Accepted Transaction Sets |
Transaction Set Trailer
SE*6*0001~
| Position | Value | Name | Meaning |
|---|---|---|---|
| SE-01 | 6 | Number of Included Segments | |
| SE-02 | 0001 | Transaction Set Control Number |
Functional Group Trailer
GE*1*89~
| Position | Value | Name | Meaning |
|---|---|---|---|
| GE-01 | 1 | Number of Transaction Sets Included | |
| GE-02 | 89 | Group Control Number |
Interchange Control Trailer
IEA*1*000000089~
| Position | Value | Name | Meaning |
|---|---|---|---|
| IEA-01 | 1 | Number of Included Functional Groups | |
| IEA-02 | 000000089 | Interchange Control Number |
Let's break this down.
The envelope segments (ISA, GS, GE, IEA) work the same way as they do in any other EDI document - see the Envelopes section for the full breakdown. The interesting parts of the 997 are the four AK segments inside the transaction set: AK1, AK2, AK5, and AK9.
AK1*GF*52 is the
Functional Group Response Header. It identifies which
functional group is being acknowledged.
AK1-01: GF
The functional identifier code from the original group's GS-01.
"GF" means "Response to a Load Tender", i.e. this 997 is
acknowledging a group of 990 documents.
AK1-02: 52
The group control number from the original group's GS-06.
This is how the sender of the 990 knows which functional group
this 997 is responding to.
AK1
View the AK1 segment in the X12 Reference
AK2*990*00000052 is the
Transaction Set Response Header. A functional group can
contain multiple transaction sets, so AK2 identifies which transaction
set within the group is being acknowledged.
AK2-01: 990
The transaction set identifier code (matches ST-01 from the
original 990).
AK2-02: 00000052
The transaction set control number (matches ST-02 from the
original 990).
AK2
View the AK2 segment in the X12 Reference
AK5*A is the
Transaction Set Response Trailer. It reports the result
for the transaction set named in AK2.
AK5-01: A
Transaction Set Acknowledgment Code. "A" means Accepted.
Other common codes include "E" (accepted with errors) and
"R" (rejected).
AK5
View the AK5 segment in the X12 Reference
Together, AK2 and AK5 form a loop: if the original functional group contained five transaction sets, the 997 would contain five AK2/AK5 pairs, one per transaction set, each reporting the result for its corresponding transaction set.
Finally, AK9*A*1*1*1 is the
Functional Group Response Trailer. It summarizes the
result for the entire functional group.
AK9-01: A Functional Group Acknowledge Code. "A" means Accepted.
AK9-02: 1 Number of Transaction Sets Included (the original group
said it contained 1 transaction set).
AK9-03: 1 Number of Received Transaction Sets (we received 1).
AK9-04: 1 Number of Accepted Transaction Sets (we accepted 1).
AK9
View the AK9 segment in the X12 Reference
If a transaction set had been rejected - say, because of a missing required segment - the AK5 for that transaction set would contain "R" instead of "A", and the AK9 totals would reflect that. The 997 can also include AK3 and AK4 segments inside the AK2/AK5 loop to pinpoint exactly which segment or element caused the problem, but those only appear when something went wrong.
Most trading partners expect 997s, so you'll be expected to generate one whenever you receive an EDI document, often within a specific SLA (commonly 24 hours). Conversely, when you send EDI documents, it's your job to fetch the 997s your trading partner generates in response, correlate them with what you've sent, and surface that in your system. For instance, if your accounting team sends invoices via EDI, the UI should indicate whether receipt of the invoice has been acknowledged.
AS2
Applicability Statement 2 () is a protocol for exchanging EDI (and other business documents) over HTTP. Unlike SFTP, where you connect to a server and drop files into folders, AS2 works more like sending an email: you POST a document directly to your trading partner's AS2 endpoint, and they POST documents back to yours. Both parties run their own AS2 server, and each side needs to know the other's URL.
AS2 is popular in retail. Walmart, Target, and many of their peers require it. If you're integrating with large retailers, you will almost certainly encounter AS2 sooner rather than later.
Certificates
Where SFTP relies on usernames, passwords, and SSH keys, AS2 relies on X.509 certificates - the same kind of certificates used for HTTPS. Each trading partner has a certificate (the public half of which they share with you), and you have a certificate (the public half of which you share with them). These certificates are used for two things:
- Encryption: the sender encrypts the payload with the recipient's public certificate, so only the recipient (with their private key) can decrypt it.
- Signing: the sender signs the payload with their own private key, so the recipient can verify it really came from them.
Certificates expire, typically every one to two years. When a trading partner's certificate expires, you'll need to install their new one before exchanging documents, otherwise signature verification will fail. Likewise, you need to give your trading partners advance notice when your certificate is about to expire so they can update their systems. Forgetting to rotate certificates is one of the most common causes of AS2 outages.
MDNs
AS2 includes a built-in acknowledgment mechanism called the Message Disposition Notification, or . When you POST an EDI document to a trading partner's AS2 endpoint, they respond with an MDN confirming that they received and successfully decrypted the message. MDNs can be synchronous (returned in the HTTP response to your POST) or asynchronous (delivered via a separate POST back to your AS2 endpoint, sometimes minutes or hours later).
The MDN is a transport-level acknowledgment: it confirms the document arrived intact. It does not confirm that the EDI document inside parsed correctly. That's still the job of the 997.
IPs and Endpoints
Like SFTP, AS2 connections are often firewalled, so you'll need to provide your trading partners with the static IPs your AS2 server uses. You'll also need a publicly accessible URL for your AS2 endpoint, with a valid TLS certificate. Most large retailers will run a connectivity test with you during onboarding to confirm that messages can flow in both directions and that MDNs are returned correctly.
Value-Added Networks
Value-added networks (VANs) are an unusual facet - some might say relic - of the EDI industry.
A is, essentially, a private data exchange service for EDI. Instead of connecting directly to your trading partners, you connect to your VAN, and your trading partners connect to theirs. The VANs handle delivery between each other behind the scenes.
In EDI, this was a genuinely useful service in the 1980s and 1990s, when point-to-point connections between businesses were expensive and unreliable. Rather than maintaining dozens of dialup or leased-line connections to each of your trading partners, you maintained one connection to a VAN, and the VAN took care of the rest.
When you and your trading partner are on the same VAN, the VAN routes documents internally between your two mailboxes. A mailbox is exactly what it sounds like: a place where inbound documents pile up until you fetch them, and where you drop outbound documents for the VAN to deliver.
When you and your trading partner are on different VANs, the two VANs use an interconnect to pass documents between each other. From your perspective, this is invisible (you still just talk to your own VAN) but it's worth knowing because interconnect issues are a common source of mysterious "my document never arrived" tickets.
Depending on how your VAN connection is set up, you may end up with a general "mailbox" that handles inbound and outbound EDI for multiple trading partners. When you get connected to your first trading partner via the VAN, it will work the same way you're used to working with SFTP: you send and receive documents via that connection.
But beware: if you add a second trading partner that is VAN-connected (even if you agreed to exchange documents via SFTP, in some cases!), their documents may start landing in the same VAN mailbox as documents from your first trading partner. In other words, the documents Acme Trucking was receiving from Waldo Mart will suddenly start getting mixed in with documents from Trader Bob's.
This is where envelopes come in. As discussed in the Envelopes section, the sender and receiver are defined in the ISA segment, in elements 05/06 (sender qualifier and ID) and 07/08 (receiver qualifier and ID). To route documents correctly in this type of VAN situation, you'll need to read those elements and route the data appropriately.
So do VANs really add value, i.e. do they live up to the name? They certainly add value to their owners, but unless you're privileged enough to belong to the VAN-owning club, which could be fairly dubbed an oligopoly, your experience will consist more of value extraction than addition. That's one reason VANs are declining in popularity as companies opt for connections they can manage themselves via secure, open standards like SFTP.
FTP and FTPS
File Transfer Protocol () is the ancestor of SFTP, and the two are often confused, but they are very different protocols. FTP dates back to 1971 and was designed in an era when the internet was a small network of research institutions who trusted each other. It transmits everything, including usernames and passwords, in plain text with no encryption whatsoever. Anyone able to observe network traffic between you and an FTP server can capture your credentials and read your documents.
For EDI, this is a serious problem. Sending EDI documents over FTP is like mailing your invoices on the back of a postcard.
is FTP over SSL/TLS and was developed as an answer to FTP's security problems. It wraps the FTP protocol in a TLS tunnel, the same encryption layer used by HTTPS, so credentials and payloads are no longer visible on the wire. Confusingly, FTPS is not the same thing as SFTP, even though the names are nearly identical:
- FTP is unencrypted FTP.
- FTPS is FTP wrapped in TLS.
- SFTP is a completely different protocol that runs over SSH.
In practice, you should treat plain FTP as obsolete and refuse to use it for EDI. If a trading partner insists on FTP, push back: ask for SFTP, FTPS, or AS2 instead. Most will agree, because their own security teams will have the same concerns. If you absolutely cannot avoid FTP, which is rare but not unheard of, particularly with smaller or older trading partners, you should at minimum restrict the connection to a dedicated, locked-down environment, and consider tunnelling it through a VPN.
FTPS is acceptable from a security standpoint, but it's much less common than SFTP in modern EDI, and it has its own operational quirks (active vs. passive mode, separate control and data channels, firewall complexity). When you have a choice, prefer SFTP.
APIs
If all of this complexity makes you wish you could handle transport using clean, simple APIs, I hear you, and that's one of the key reasons I built Tediware. Tediware turns the messy world of EDI transport - SFTP folders, AS2 certificates, VAN mailboxes, firewalls - into a single, API-driven process flow.
Specifically, Tediware handles:
- Static IPs for outbound connections, so you don't have to set up your own NAT gateway every time a trading partner asks for an IP to whitelist.
- Protocol normalization: every connection type, regardless of the underlying protocol, looks the same from your code's perspective.
- Automatic 997 acknowledgments: Tediware can automatically generate 997s for incoming documents.
- Automatic routing of documents based on the ISA envelope, so VAN scenarios with mixed trading partner traffic just work.
- Certificate management for AS2, with a super simple GUI.
- Retry and backoff for transient connection failures, with visibility into what was retried and why.
- Audit trail for every document sent and received, including the raw payload, the protocol used, and the trace through your processing pipeline.
- Webhooks when documents arrive, so you can react to inbound EDI in real time instead of polling.
In short: Tediware lets you treat EDI like a modern API, while still speaking fluent SFTP, AS2, and VAN under the hood.