# Accounts and billing Learn how to manage Stedi accounts, members, billing, and payments. ## Accounts A Stedi account is a container for all of your Stedi activity and resources. Every account has a unique ID which you can find in the [Account profile](https://www.stedi.com/app/settings/account-details). This ID is used to identify the account in the API and in the dashboard. It is also used in dashboard URLs, where it appears in the `account` URL parameter. Accounts can have unlimited members, and members can be [assigned different roles](#assigning-member-roles) with different permissions. It's possible to have multiple accounts, though using one account is recommended for most customers. If you need additional accounts, you can reach out to [support](https://www.stedi.com/contact) and we'll enable them for you. Note that accounts cannot be linked – all settings and membership are specific to a given account. You cannot delete an account via the dashboard or the API. If you need to delete an account, first delete all data and resources in the account then [contact support](https://www.stedi.com/contact). ### Settings To access your user account settings, click your user account icon in the top right of the app. You can set the Stedi app to **Light** or **Dark** mode and enable Multi-Factor Authentication (MFA) for your user account. To access your Stedi account settings, click the account name and select **Account settings**. You can view the account name, account ID, and require Multi-Factor Authentication (MFA) for all account users. ### Inviting members You can add members in [member settings](https://www.stedi.com/app/settings/members). Each time you invite a member, they will receive an email with your invitation. Invitations do not expire, but can be revoked by any account admin at any time before acceptance. ### Removing members Any account admin can remove other members from an account. Removed users will still retain their Stedi user credentials and access to other accounts of which they're a member. ### Assigning member roles Admins can use role-based access control (RBAC) to ensure only authorized users can access and modify resources in a Stedi account. Admins can assign Stedi account members to one of four roles: * **Admin:** These users can access and modify all resources within a Stedi account. This includes adding and removing members, assigning member roles, adding billing information, configuring settings, generating EDI files, and configuring resources. * **Developer:** These users can access and configure all resources. * **Operator:** These users can access and configure Partnerships, Guides, and Mappings. They can interact with developer resources, but cannot modify them. Operator is the minimum required role for a user to interact with Stedi's Healthcare APIs and review transactions (such as completed eligibility checks) in the Stedi app. * **Read-only:** These users can view some account resources, but cannot modify them. For example, they can review processed transactions in Stedi's interface but cannot call the API. To change a member's role: 1. Go to [member settings](https://www.stedi.com/app/settings/members) in your account. 2. Click the pencil icon for a member, choose the appropriate **Role** from the list, and click **Update role**. ### Enabling Multi-Factor Authentication (MFA) You can enable Multi-Factor Authentication (MFA) for your user account. To enable MFA, click your user account icon in the top right of the app and then click **Enable 2FA**. You can also require **all** users to enable MFA before accessing a Stedi account. To enforce MFA for all users: 1. Click the account name. 2. Select **Account settings** and toggle MFA to **ON**. The next time a user logs into the Stedi account, Stedi prompts them to set up their MFA token: [https://www.stedi.com/auth/setup-mfa](https://www.stedi.com/auth/setup-mfa) Once you enable MFA for a Stedi account, it cannot be disabled. ## Billing and payment Each account will be invoiced monthly. To add or edit your payment details, you can navigate to the [Payment methods](https://www.stedi.com/app/billing/payment-methods) page in your account and click **Manage billing**. Charges will be billed to the credit card on file. # Get Execution core get /executions/{executionId} Retrieve the file execution details for a given executionId. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/executions/{executionId} \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "createdAt": "2023-08-28T09:00:24.965Z", "direction": "INBOUND", "executionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "faultCount": 0, "partnershipId": "i-am-another-merch_this-is-me", "source": { "name": "my-execution-file.edi" }, "retryable": true, "status": "COMPLETED", "transactionCount": 1, "updatedAt": "2023-08-28T09:00:28.741Z" } ``` # Get Execution Input core get /executions/{executionId}/input This endpoint retrieves an execution's input document before it passes through any translation and mappings. There are no size restrictions on documents when fetching from this endpoint. ## Response This endpoint returns a `302` Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, the `-L` or `--location` flags in cURL requests will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is available for 60 minutes. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/executions/{executionId}/input \ --header "Authorization: ${STEDI_API_KEY}" ``` ```text Response 200: Inbound ST*855*0001~ BAK*00*AD*365465413*20220914*****20220913~ REF*CO*ACME-4567~ N1*SE*Marvin Acme*92*DROPSHIP CUSTOMER~ N3*123 Main Street~ N4*Fairfield*NJ*07004*US~ N1*ST*Wile E Coyote*92*DROPSHIP CUSTOMER~ N3*111 Canyon Court~ N4*Phoenix*AZ*85001*US~ PO1*item-1*8*EA*400**VC*VND1234567*SK*ACM/8900-400~ PID*F****400 pound anvil~ ACK*IA*8*EA~ PO1*item-2*4*EA*125**VC*VND000111222*SK*ACM/1100-001~ PID*F****Detonator~ ACK*IA*4*EA~ CTT*2~ SE*17*0001% ``` ```json Response 200: Outbound { "heading": { "transaction_set_header_ST": { "transaction_set_identifier_code_01": "850", "transaction_set_control_number_02": 1 }, "beginning_segment_for_purchase_order_BEG": { "transaction_set_purpose_code_01": "XX", "purchase_order_type_code_02": "XX", "purchase_order_number_03": "XXXXX", "date_05": "2023-08-11" } }, "detail": { "baseline_item_data_PO1_loop": [ { "baseline_item_data_PO1": {} } ] }, "summary": { "transaction_set_trailer_SE": { "number_of_included_segments_01": 4, "transaction_set_control_number_02": 1 } } } ``` # Get Execution Metadata core get /executions/{executionId}/metadata This endpoint retrieves an execution's metadata document. There are no size restrictions on documents when fetching from this endpoint. ## Response This endpoint returns a 302 Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, using the `-L` or `--location` flag in cURL will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is available for 60 minutes. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/executions/{executionId}/metadata \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Example X12 metadata response { "version": "2024-01-01", "interchanges": [ { "envelope": { "senderQualifier": "ZZ", "senderId": "BSW ", "receiverQualifier": "ZZ", "receiverId": "ACME ", "date": "2022-05-24", "time": "20:01", "versionNumberCode": "00401", "controlNumber": 93, "acknowledgmentRequestedCode": "0", "usageIndicatorCode": "P", "trailer": { "numberOfIncludedFunctionalGroups": 1, "controlNumber": 93 }, "segments": { "isa": "ISA*00* *00* *ZZ*BSW *ZZ*ACME *220524*2001*U*00401*000000093*0*P*>", "iea": "IEA*1*000000093" } }, "acknowledgments": [], "standard": "x12", "span": { "start": 0, "end": 715 }, "delimiters": { "segment": "~", "element": "*", "composite": ">" }, "functionalGroups": [ { "envelope": { "functionalIdentifierCode": "SH", "applicationSenderCode": "BSW", "applicationReceiverCode": "ACME", "date": "2022-05-24", "time": "20:01", "controlNumber": 97, "responsibleAgencyCode": "X", "release": "004010", "trailer": { "numberOfIncludedTransactionSets": 1, "controlNumber": 97 }, "segments": { "gs": "GS*SH*BSW*ACME*20220524*2001*97*X*004010", "ge": "GE*1*97" } }, "span": { "start": 104, "end": 698 }, "transactionSets": [ { "id": "856", "controlNumber": "0001", "trailer": { "numberOfIncludedSegments": 18, "controlNumber": "0001" }, "span": { "start": 154, "end": 689 }, "trackedIdentifiers": { "PRF-01": ["Tx22HNv4d"], "BSN-02": ["VendorShipID"] } } ] } ] } ] } ``` # Get Execution Output core get /executions/{executionId}/output This endpoint retrieves an execution's output document. There are no size restrictions on documents when fetching from this endpoint. You can only call this endpoint for outbound files that you send to your trading partner. If you call the API for an inbound file, the endpoint returns a `404` Not Found response. ## Response This endpoint returns a `302` Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, the `-L` or `--location` flags in cURL requests will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` that contains a temporary URL to download the document. This URL is available for 60 minutes. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/executions/{executionId}/output \ --header "Authorization: ${STEDI_API_KEY}" ``` ```text Response 200: Outbound ST*855*0001~ BAK*00*AD*365465413*20220914*****20220913~ REF*CO*ACME-4567~ N1*SE*Marvin Acme*92*DROPSHIP CUSTOMER~ N3*123 Main Street~ N4*Fairfield*NJ*07004*US~ N1*ST*Wile E Coyote*92*DROPSHIP CUSTOMER~ N3*111 Canyon Court~ N4*Phoenix*AZ*85001*US~ PO1*item-1*8*EA*400**VC*VND1234567*SK*ACM/8900-400~ PID*F****400 pound anvil~ ACK*IA*8*EA~ PO1*item-2*4*EA*125**VC*VND000111222*SK*ACM/1100-001~ PID*F****Detonator~ ACK*IA*4*EA~ CTT*2~ SE*17*0001% ``` # Get Execution Transactions core get /executions/{executionId}/transactions Fetch a list of transactions for a given file execution, sorted by the date they were created from newest to oldest. Includes the full transaction details. ```bash Request curl --request GET \ --url https://core.us.stedi.com/2023-08-01/executions/{executionId}/transactions \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "items": [ { "direction": "OUTBOUND", "mode": "production", "fileExecutionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "transactionId": "a15b68ca-fae0-42de-b8a3-f436668b8604", "processedAt": "2023-08-28T09:00:28.354Z", "artifacts": [ { "artifactType": "application/json", "sizeBytes": 490, "usage": "input", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/input" }, { "artifactType": "application/edi-x12", "sizeBytes": 51, "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/output" } ], "partnership": { "partnershipId": "i-am-another-merch_this-is-me", "partnershipType": "x12", "sender": { "profileId": "i-am-another-merch" }, "receiver": { "profileId": "this-is-me" } }, "x12": { "metadata": { "interchange": { "acknowledgmentRequestedCode": "1", "controlNumber": 2 }, "functionalGroup": { "controlNumber": 2, "release": "008010", "date": "2023-08-28", "time": "09:00:20", "functionalIdentifierCode": "PO" }, "transaction": { "controlNumber": "1", "transactionSetIdentifier": "850" }, "receiver": { "applicationCode": "THISISME", "isa": { "qualifier": "ZZ", "id": "THISISME" } }, "sender": { "applicationCode": "ANOTHERMERCH", "isa": { "qualifier": "14", "id": "ANOTHERMERCH" } } }, "transactionSetting": { "guideId": "01H8PSWG4ZD6QPKC9VSD42PQX3", "transactionSettingId": "005010-850" } } } ] } ``` # List Executions core get /executions Fetch a list of executions, sorted by the date they were created from newest to oldest. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/executions \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "items": [ { "createdAt": "2023-08-28T09:00:24.965Z", "direction": "OUTBOUND", "executionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "faultCount": 0, "partnershipId": "i-am-another-merch_this-is-me", "source": { "name": "my-execution-file.edi" }, "retryable": true, "status": "COMPLETED", "transactionCount": 1, "updatedAt": "2023-08-28T09:00:28.741Z" }, { "createdAt": "2023-08-28T09:17:38.591Z", "direction": "OUTBOUND", "executionId": "1bdbfae4-b30e-cab8-d90f-6fd61ef3d1da", "faultCount": 0, "partnershipId": "i-am-another-merch_this-is-me", "source": { "name": "my-execution-file.edi" }, "retryable": true, "status": "COMPLETED", "transactionCount": 1, "updatedAt": "2023-08-28T09:17:44.570Z" } ], "nextPageToken": "945ff6de213d3ef481d028065d4c12fb996a166a3a90ef98564318decfae50ce4b36d74b7e9d9bafa6e1d169" } ``` # List Transactions core get /transactions Fetch a list of transactions, sorted by the date they were created from newest to oldest. Generally this endpoint is used to display a list of transactions in a UI. If you are looking to regularly fetch and check for new transactions for programmatic usage, you should use the `ListPollingTransactions` operation instead. ```bash Request curl --request GET \ --url https://core.us.stedi.com/2023-08-01/transactions \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "items": [ { "direction": "OUTBOUND", "mode": "production", "fileExecutionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "transactionId": "a15b68ca-fae0-42de-b8a3-f436668b8604", "processedAt": "2023-08-28T09:00:28.354Z", "artifacts": [ { "artifactType": "application/json", "sizeBytes": 490, "usage": "input", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/input" }, { "artifactType": "application/edi-x12", "sizeBytes": 51, "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/output" } ], "partnership": { "partnershipId": "i-am-another-merch_this-is-me", "partnershipType": "x12", "sender": { "profileId": "i-am-another-merch" }, "receiver": { "profileId": "this-is-me" } }, "businessIdentifiers": [ { "element": "PRF-01", "name": "Purchase Order Number", "value": "T000HNb4d" } ], "x12": { "metadata": { "interchange": { "acknowledgmentRequestedCode": "1", "controlNumber": 2 }, "functionalGroup": { "controlNumber": 2, "release": "008010", "date": "2023-08-28", "time": "09:00:20", "functionalIdentifierCode": "PO" }, "transaction": { "controlNumber": "1", "transactionSetIdentifier": "850" }, "receiver": { "applicationCode": "THISISME", "isa": { "qualifier": "ZZ", "id": "THISISME" } }, "sender": { "applicationCode": "ANOTHERMERCH", "isa": { "qualifier": "14", "id": "ANOTHERMERCH" } } }, "transactionSetting": { "guideId": "01H8PSWG4ZD6QPKC9VSD42PQX3", "transactionSettingId": "005010-850" } } } ], "nextPageToken": "be08e5ba4bf36da9da27dcb651e64a6e5502685499994f354" } ``` # Poll Executions core get /polling/executions This endpoint is used to regularly poll for new executions that have been processed by Stedi. You must define one of `startDateTime` or `pageToken` when making a request. You may optionally define a `pageSize`. The minimum `pageSize` is 1, and the maximum `pageSize` is 1000. The default is 100. `startDateTime` takes a string in ISO 8601 format. (ex: `2023-08-10T18:00:00Z`). `startDateTime` must be set to at least 1 minute in the past. The results will contain executions that occurred after this `startDateTime`. Starting from the oldest to newest executions ordered by the `processedAt` field. Note, this is _exclusive_ of the `startDateTime`, a execution occuring at exactly `2023-08-10T18:00:00Z` for instance, would not be included. In addition, there is a 15 second window where newly created executions will not be included to account for any network latency or clock drifts within the systems to ensure you do not miss any executions. Each request will _always_ return a `nextPageToken`, regardless of whether there are new executions or not. We DO NOT recommend trying to roll your own polling strategy leveraging `startDateTime` only. There are edge cases around two executions occuring at the _exact_ same time and being on the edge of a pagination which could cause you to miss one due to the exclusive nature of `startDateTime`. We recommend using `pageToken`'s instead. When making subsequent polling requests (not initiating with `startDateTime`), the `pageToken` can be used to continue iterating through pages of executions. Usage of the `pageToken` guaruntees you will not miss any executions on the stream. If at any point there are no more new executions in the `item` array, you will still receive a `nextPageToken`. Continue to use this token to poll for new executions. Once there are new executions, they will be returned in the `item` array. `pageToken`'s you have retrieved can serve as checkpoints. They do not expire, and you can always start from that point in the execution stream again if you need to catch a system up or recover from a failure. Storing `pageToken`'s as part of your polling process is encouraged. `pageToken`'s are unique per request, opaque, and should not be parsed or modified in any way. They are not guaranteed to be in any particular format, and may change in the future. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/polling/executions?startDateTime=2023-08-28T00:00:00Z \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "items": [ { "createdAt": "2023-08-28T09:00:24.965Z", "direction": "OUTBOUND", "executionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "faultCount": 0, "partnershipId": "i-am-another-merch_this-is-me", "retryable": true, "status": "COMPLETED", "transactionCount": 1, "updatedAt": "2023-08-28T09:00:28.741Z" }, { "createdAt": "2023-08-28T09:17:38.591Z", "direction": "OUTBOUND", "executionId": "1bdbfae4-b30e-cab8-d90f-6fd61ef3d1da", "faultCount": 0, "partnershipId": "i-am-another-merch_this-is-me", "retryable": true, "status": "COMPLETED", "transactionCount": 1, "updatedAt": "2023-08-28T09:17:44.570Z" } ], "nextPageToken": "945ff6de213d3ef481d028065d4c12fb996a166a3a90ef98564318decfae50ce4b36d74b7e9d9bafa6e1d169" } ``` # Poll transactions core get /polling/transactions This endpoint is used to regularly poll for new transactions that have been processed in Core. You must define one of `startDateTime` or `pageToken` when making a request. You may optionally define a `pageSize`. The minimum `pageSize` is 1, and the maximum `pageSize` is 1000. The default is 100. `startDateTime` takes a string in ISO 8601 format. (ex: `2023-08-10T18:00:00Z`). `startDateTime` must be set to at least 1 minute in the past. The results will contain transactions that occurred after this `startDateTime`. Starting from the oldest to newest transactions ordered by the `processedAt` field. Note, this is _exclusive_ of the `startDateTime`, a transaction occuring at exactly `2023-08-10T18:00:00Z` for instance, would not be included. In addition, there is a 15 second window where newly created transactions will not be included to account for any network latency or clock drifts within the systems to ensure you do not miss any transactions. Each request will _always_ return a `nextPageToken`, regardless of whether there are new transactions or not. We DO NOT recommend trying to roll your own polling strategy leveraging `startDateTime` only. There are edge cases around two transactions occuring at the _exact_ same time and being on the edge of a pagination which could cause you to miss one due to the exclusive nature of `startDateTime`. We recommend using `pageToken`'s instead. When making subsequent polling requests (not initiating with `startDateTime`), the `pageToken` can be used to continue iterating through pages of transactions. Usage of the `pageToken` guaruntees you will not miss any transactions on the stream. If at any point there are no more new transactions in the `item` array, you will still receive a `nextPageToken`. Continue to use this token to poll for new transactions. Once there are new transactions, they will be returned in the `item` array. `pageToken`'s you have retrieved can serve as checkpoints. They do not expire, and you can always start from that point in the transaction stream again if you need to catch a system up or recover from a failure. Storing `pageToken`'s as part of your polling process is encouraged. `pageToken`'s are unique per request, opaque, and should not be parsed or modified in any way. They are not guaranteed to be in any particular format, and may change in the future. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/polling/transactions?startDateTime=2023-08-28T00:00:00Z \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "items": [ { "direction": "OUTBOUND", "mode": "production", "fileExecutionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "transactionId": "a15b68ca-fae0-42de-b8a3-f436668b8604", "processedAt": "2023-08-28T09:00:28.354Z", "artifacts": [ { "artifactType": "application/json", "sizeBytes": 490, "usage": "input", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/input" }, { "artifactType": "application/edi-x12", "sizeBytes": 51, "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/output" } ], "partnership": { "partnershipId": "i-am-another-merch_this-is-me", "partnershipType": "x12", "sender": { "profileId": "i-am-another-merch" }, "receiver": { "profileId": "this-is-me" } }, "businessIdentifiers": [ { "element": "PRF-01", "name": "Purchase Order Number", "value": "T000HNb4d" } ], "x12": { "metadata": { "interchange": { "acknowledgmentRequestedCode": "1", "controlNumber": 2 }, "functionalGroup": { "controlNumber": 2, "release": "008010", "date": "2023-08-28", "time": "09:00:20", "functionalIdentifierCode": "PO" }, "transaction": { "controlNumber": "1", "transactionSetIdentifier": "850" }, "receiver": { "applicationCode": "THISISME", "isa": { "qualifier": "ZZ", "id": "THISISME" } }, "sender": { "applicationCode": "ANOTHERMERCH", "isa": { "qualifier": "14", "id": "ANOTHERMERCH" } } }, "transactionSetting": { "guideId": "01H8PSWG4ZD6QPKC9VSD42PQX3", "transactionSettingId": "005010-850" } } } ], "nextPageToken": "945ff6de213d3ef481d028065d4c12fb996a166a3a90ef98564318decfae50ce4b36d74b7e9d9bafa6e1d169" } ``` # Get Fragment core get /transactions/{transactionId}/fragments/{fragmentIndex} This endpoint fetches a fragment by its index for a given transaction. This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. ```bash Request curl --request GET \ --url https://core.us.stedi.com/2023-08-01/transactions/{transactionId}/fragments/{fragmentIndex} \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "direction": "INBOUND", "mode": "production", "fileExecutionId": "29d6b95d-c611-bce6-b893-0e64821cd238", "transactionId": "7d0c6f84-4cec-4f4a-a681-e7a36eb48d25", "processedAt": "2023-10-12T15:34:01.435Z", "partnership": { "partnershipId": "me_another-merch", "partnershipType": "x12", "sender": { "profileId": "merch" }, "receiver": { "profileId": "me" } }, "x12": { "metadata": { "interchange": { "acknowledgmentRequestedCode": "0", "controlNumber": 103 }, "functionalGroup": { "controlNumber": 103, "release": "005010X220A1", "date": "2004-12-27", "time": "13:24", "functionalIdentifierCode": "BE" }, "transaction": { "controlNumber": "13331", "transactionSetIdentifier": "846" }, "receiver": { "applicationCode": "THISISME", "isa": { "qualifier": "02", "id": "THISISME" } }, "sender": { "applicationCode": "ANOTHERMERCH", "isa": { "qualifier": "02", "id": "ANOTHERMERCH" } } }, "transactionSetting": { "guideId": "01HAPYY1YPFWGVJH1HD75SP0A2", "transactionSettingId": "01HCAHP7PY84DBZG0FM5JB4MCE" } }, "fragments": { "batchSize": 800, "keyName": "item_identification_LIN_loop", "fragmentCount": 1065 }, "fragmentIndex": 0, "artifacts": [ { "artifactType": "application/json", "sizeBytes": 389388, "model": "fragment", "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/7d0c6f84-4cec-4f4a-a681-e7a36eb48d25/fragments/0/output" } ], "transactionUrl": "https://core.us.stedi.com/2023-08-01/transactions/7d0c6f84-4cec-4f4a-a681-e7a36eb48d25" } ``` # Get Fragment Output core get /transactions/{transactionId}/fragments/{fragmentIndex}/output This endpoint retrieves a transaction fragment's output document after it has been translated. There are no size restrictions on documents when fetching from this endpoint, however they are generally smaller and consumable because they are fragments. ## Response This endpoint returns a `302` Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, using the `-L` or `--location` flag in cURL will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is available for 60 minutes. This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. ```bash Request curl --request GET \ --url https://core.us.stedi.com/2023-08-01/transactions/{transactionId}/fragments/{fragmentIndex}/output \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "item_identification_LIN_loop": [ { "item_identification_LIN": { "assigned_identification_01": "1", "product_service_id_qualifier_02": "VC", "product_service_id_03": "AAD15-1000" }, "quantity_information_QTY_loop": [ { "quantity_information_QTY": { "quantity_qualifier_01": "17", "quantity_02": 0, "composite_unit_of_measure_03": { "unit_or_basis_for_measurement_code_01": "EA" } } }, { "quantity_information_QTY": { "quantity_qualifier_01": "ZZ", "quantity_02": 179.45, "composite_unit_of_measure_03": { "unit_or_basis_for_measurement_code_01": "DO" } } } ] }, { "item_identification_LIN": { "assigned_identification_01": "2", "product_service_id_qualifier_02": "VC", "product_service_id_03": "AAD15-2" }, "quantity_information_QTY_loop": [ { "quantity_information_QTY": { "quantity_qualifier_01": "17", "quantity_02": 0, "composite_unit_of_measure_03": { "unit_or_basis_for_measurement_code_01": "EA" } } }, { "quantity_information_QTY": { "quantity_qualifier_01": "ZZ", "quantity_02": 179.45, "composite_unit_of_measure_03": { "unit_or_basis_for_measurement_code_01": "DO" } } } ] } ] } ``` # Get Transaction core get /transactions/{transactionId} Fetch a single transaction by its ID. ```bash Request curl --request GET \ --url https://core.us.stedi.com/2023-08-01/transactions/{transactionId} \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200 { "direction": "OUTBOUND", "mode": "production", "fileExecutionId": "f75168e4-e682-4410-bfec-b5b1541c7f21", "transactionId": "a15b68ca-fae0-42de-b8a3-f436668b8604", "processedAt": "2023-08-28T09:00:28.354Z", "artifacts": [ { "artifactType": "application/json", "sizeBytes": 490, "usage": "input", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/input" }, { "artifactType": "application/edi-x12", "sizeBytes": 51, "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/a15b68ca-fae0-42de-b8a3-f436668b8604/output" } ], "partnership": { "partnershipId": "i-am-another-merch_this-is-me", "partnershipType": "x12", "sender": { "profileId": "i-am-another-merch" }, "receiver": { "profileId": "this-is-me" } }, "x12": { "metadata": { "interchange": { "acknowledgmentRequestedCode": "1", "controlNumber": 2 }, "functionalGroup": { "controlNumber": 2, "release": "008010", "date": "2023-08-28", "time": "09:00:20", "functionalIdentifierCode": "PO" }, "transaction": { "controlNumber": "1", "transactionSetIdentifier": "850" }, "receiver": { "applicationCode": "THISISME", "isa": { "qualifier": "ZZ", "id": "THISISME" } }, "sender": { "applicationCode": "ANOTHERMERCH", "isa": { "qualifier": "14", "id": "ANOTHERMERCH" } } }, "transactionSetting": { "guideId": "01H8PSWG4ZD6QPKC9VSD42PQX3", "transactionSettingId": "005010-850" } } } ``` # Get Transaction Input core get /transactions/{transactionId}/input This endpoint retrieves a transaction's input document before it passes through any translation and mappings. There are no size restrictions on documents when fetching from this endpoint. ## Response This endpoint returns a `302` Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, using the `-L` or `--location` flag in cURL will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is available for 60 minutes. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/transactions/{transactionId}/input \ --header "Authorization: ${STEDI_API_KEY}" ``` ```text Response 200: Inbound ST*855*0001~ BAK*00*AD*365465413*20220914*****20220913~ REF*CO*ACME-4567~ N1*SE*Marvin Acme*92*DROPSHIP CUSTOMER~ N3*123 Main Street~ N4*Fairfield*NJ*07004*US~ N1*ST*Wile E Coyote*92*DROPSHIP CUSTOMER~ N3*111 Canyon Court~ N4*Phoenix*AZ*85001*US~ PO1*item-1*8*EA*400**VC*VND1234567*SK*ACM/8900-400~ PID*F****400 pound anvil~ ACK*IA*8*EA~ PO1*item-2*4*EA*125**VC*VND000111222*SK*ACM/1100-001~ PID*F****Detonator~ ACK*IA*4*EA~ CTT*2~ SE*17*0001% ``` ```json Response 200: Outbound { "heading": { "transaction_set_header_ST": { "transaction_set_identifier_code_01": "850", "transaction_set_control_number_02": 1 }, "beginning_segment_for_purchase_order_BEG": { "transaction_set_purpose_code_01": "XX", "purchase_order_type_code_02": "XX", "purchase_order_number_03": "XXXXX", "date_05": "2023-08-11" } }, "detail": { "baseline_item_data_PO1_loop": [ { "baseline_item_data_PO1": {} } ] }, "summary": { "transaction_set_trailer_SE": { "number_of_included_segments_01": 4, "transaction_set_control_number_02": 1 } } } ``` # Get Transaction Output core get /transactions/{transactionId}/output This endpoint retrieves a transaction's output document after it has been translated. There are no size restrictions on documents when fetching from this endpoint. ## Response This endpoint returns a `302` Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For example, using the `-L` or `--location` flag in cURL will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the response contains a JSON object with a single key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is available for 60 minutes. ```bash Request curl --request GET -L \ --url https://core.us.stedi.com/2023-08-01/transactions/{transactionId}/output \ --header "Authorization: ${STEDI_API_KEY}" ``` ```json Response 200: Inbound { "heading": { "transaction_set_header_ST": { "transaction_set_identifier_code_01": "850", "transaction_set_control_number_02": 1 }, "beginning_segment_for_purchase_order_BEG": { "transaction_set_purpose_code_01": "XX", "purchase_order_type_code_02": "XX", "purchase_order_number_03": "XXXXX", "date_05": "2023-08-11" } }, "detail": { "baseline_item_data_PO1_loop": [ { "baseline_item_data_PO1": {} } ] }, "summary": { "transaction_set_trailer_SE": { "number_of_included_segments_01": 4, "transaction_set_control_number_02": 1 } } } ``` ```text Response 200: Outbound ST*855*0001~ BAK*00*AD*365465413*20220914*****20220913~ REF*CO*ACME-4567~ N1*SE*Marvin Acme*92*DROPSHIP CUSTOMER~ N3*123 Main Street~ N4*Fairfield*NJ*07004*US~ N1*ST*Wile E Coyote*92*DROPSHIP CUSTOMER~ N3*111 Canyon Court~ N4*Phoenix*AZ*85001*US~ PO1*item-1*8*EA*400**VC*VND1234567*SK*ACM/8900-400~ PID*F****400 pound anvil~ ACK*IA*8*EA~ PO1*item-2*4*EA*125**VC*VND000111222*SK*ACM/1100-001~ PID*F****Detonator~ ACK*IA*4*EA~ CTT*2~ SE*17*0001% ``` # Stage fragment post /fragments/{fragmentGroupId} This endpoint stages a fragment for outbound delivery. You can optionally specify a [mapping](/edi-platform/mappings/index) to transform the fragment to Stedi's Guide JSON format. If you don't specify a mapping, the fragment must match the [Guide JSON](/edi-platform/operate/transform-json/guide-json) format for the specified guide. [Fragments](/edi-platform/fragments) allow you to split large transactions into smaller chunks for easier processing. You can enable fragments for one repeated EDI segment in each transaction set and then split the transaction into chunks based on that segment. For example, if you enable fragments on the `LIN` loop in an 846 Inventory Inquiry/Advice, you can stage fragments containing batches of `LIN` loops. Later, when you call the Create Outbound Transaction endpoint, Stedi stitches the fragments together into a single transaction and delivers it to your trading partner. # Stage transactions post /partnerships/{partnershipId}/transaction-groups/{transactionGroupId}/transactions/{transactionSettingId} This endpoint stages a transaction for outbound delivery. This is a BETA endpoint. We may make backwards incompatible changes. Stedi stores the transaction in the transaction group specified by the `transactionGroupId`. If a group with that ID does not exist, Stedi creates one. When you're ready to send all of the transactions in the group, call the [Deliver Transaction Group](/api-reference/edi-platform/post-transaction-group) endpoint with the `transactionGroupId` to generate and deliver a fully-formed EDI file to your trading partner. ## Transaction data You provide transaction data in [Guide JSON](/edi-platform/operate/transform-json/guide-json) format. The transaction data must be \< 5MB. All of the transactions you stage in a transaction group must use the same transaction settings. If you attempt to stage a transaction with different settings, Stedi returns an error. # Map Transaction Output mappings get /mappings/{id}/map-transaction-output/{transactionId} Retrieve a mapped transaction's output document This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. This endpoint returns the mapped output of a processed inbound transaction. You can use it to retrieve processed transaction data asynchronously. ## Response The endpoint applies the specified mapping to the processed transaction and returns the fully mapped output. This endpoint returns a 202 Accepted upon receiving the initial request and while the transaction's output is being mapped in the background. Once the mapping process completes, the endpoint returns a 302 Temporary redirect to the document download URL. Many HTTP clients will automatically follow this redirect, or have a simple follow redirects configuration to set. For instance in `curl` using the `-L` or `--location` flag will automatically follow the redirect. In the event you cannot, or chose not to automatically follow the redirect, the body of the 302 response contains a JSON object with a key `documentDownloadUrl` which contains a temporary URL to download the document. This URL is good for 60 minutes. ## Size limits The recommended maximum size of the transaction output document mapped with this endpoint is 150 MB in Guide JSON format (equivalent of approximately 15 MB in raw EDI). # Retry events core post /events/{eventId}/retry This endpoint retriggers the specified processing event. The retriggered event has a new `eventId` and appears as a separate event record in the Stedi app. For example, if you retry a `transaction.processed.v2` event, the app shows two `transaction.processed.v2` events for the file. Retrying individual processing events can be helpful when testing your integration. For example, you can use this approach to retrigger [Destination webhooks](/edi-platform/configure/destinations/index) without needing to continually reprocess the same test file. ```bash Request curl --request POST -L \ --url https://core.us.stedi.com/2023-08-01/events/e8b4ddc9-96df-5df0-488d-2b489b6a8c23/retry \ --header "Authorization: ${STEDI_API_KEY}" ``` ```text Response 200 {"eventId":"ad3abd42-bf84-36da-f118-232f0c4cb931"} ``` # Create Outbound Interchange core post /x12/partnerships/{partnershipId}/generate-edi This endpoint generates and delivers fully-formed EDI files to your trading partners. When you call this endpoint, Stedi: 1. Generates a single EDI file containing all transactions according to the Stedi guide attached to each outbound transaction setting. This includes adding required envelope information (`ISA` and `GS` headers) and autogenerated control numbers. 2. Delivers the EDI file to your trading partner through the connection specified in the transaction settings. ## Transaction data You must provide transaction data in [Guide JSON](/edi-platform/operate/transform-json/guide-json) format. The transaction data must be \< 5MB. ## Delivery attempts Stedi attempts to deliver a file to all configured connections every 6 minutes for up to 3 total attempts. If it cannot deliver the file after the third attempt, it marks the file execution as `FAILED` and emits the [`file.failed.v2` event](/edi-platform/operate/event-types#file-failed). Stedi displays each delivery attempt and the failure details on the [Files](https://www.stedi.com/app/core/file-executions) page. ## Customize generated files You can change the timezone, time format, character set (which characters are allowed), and filename for generated files. [Learn more](/edi-platform/operate/generate-edi/index#timezone-and-time-format). ## Inbound processing There is no equivalent endpoint for parsing EDI files into JSON. To parse inbound files, you or your partner can send EDI files to an SFTP/FTPS or AS2 [connection](/edi-platform/configure/trading-partners/connections/index), and Stedi sends the JSON payload to the configured [Destination webhook](/edi-platform/configure/destinations/index). # Invoke Mapping mappings post /mappings/{id}/map Maps the provided JSON to a different shape according to the specified mapping definition. This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. ```bash Request curl --request POST \ --url https://mappings.us.stedi.com/2021-06-01/mappings/{mappingId}/map \ --header "Authorization: ${STEDI_API_KEY}" \ --data '{ "myData": 1 }' ``` ```json Response 200 { "mappedData": 2 } ``` # Deliver Transaction Group core post /partnerships/{partnershipId}/transaction-groups/{transactionGroupId}/generate-edi This endpoint generates and delivers a fully-formed EDI file containing the staged transactions in the specified transaction group. This is a BETA endpoint. We may make backwards incompatible changes. When you call this endpoint, Stedi: 1. Generates a single EDI file containing all transactions in the specified transaction group (`transactionGroupId`). This includes adding required envelope information (`ISA` and `GS` headers) and autogenerated control numbers. 2. Delivers the EDI file to your trading partner through the connection specified in the transaction settings. You can only call this endpoint with a given `transactionGroupId` once. Afterward, that transaction group is locked, and you must create a new transaction group to generate another file. ## Stage transactions You can use the [Stage Transactions API](/api-reference/edi-platform/core/stage-transactions) to store one or more transactions in a transaction group on Stedi. When you're ready to send all of the transactions in the group, you can call this endpoint to generate and deliver an EDI file to your trading partner. ## Delivery attempts Stedi attempts to deliver a file to all configured connections every 6 minutes for up to 3 total attempts. If it cannot deliver the file after the third attempt, it marks the file execution as `FAILED` and emits the [`file.failed.v2` event](/edi-platform/operate/event-types#file-failed). Stedi displays each delivery attempt and the failure details on the [Files](https://www.stedi.com/app/core/file-executions) page. ## Customize generated files You can change the timezone, time format, character set (which characters are allowed), and filename for generated files. [Learn more](/edi-platform/operate/generate-edi/index#timezone-and-time-format). ## Inbound processing There is no equivalent endpoint for parsing EDI files into JSON. To parse inbound files, you or your partner can send EDI files to an SFTP/FTPS or AS2 [connection](/edi-platform/configure/trading-partners/connections/index), and Stedi sends the JSON payload to the configured [Destination webhook](/edi-platform/configure/destinations/index). This endpoint generates and delivers a fully-formed EDI file for a given transaction group. Transactions are staged in a group using the `CreateTransactionGroup` endpoint. Once a file has been generated for a given transaction group, the group can no longer be used. # Create Outbound Transaction post /partnerships/{partnershipId}/transactions/{transactionSettingId} This endpoint generates and delivers fully-formed EDI files containing a single transaction. It is the simplest way to generate EDI with Stedi. When you call the endpoint, Stedi: 1. Applies the mapping (if present) to the provided transaction data. 2. Adds [fragments](/edi-platform/fragments) from specified fragment groups (if present). 3. Generates an EDI file according to the Stedi guide attached to the [outbound transaction setting](/edi-platform/configure/trading-partners/transaction-settings#create-transaction-settings). This includes adding required envelope information (`ISA` and `GS` headers) and autogenerated control numbers. 4. Delivers the EDI file to your trading partner through the [connection](/edi-platform/configure/trading-partners/connections/index) specified in the outbound transaction setting. Visit [Generate EDI](/edi-platform/operate/generate-edi/index) for step-by-step instructions to format transaction data and make requests. ## Response When you deliver a single transaction without any fragment groups, this endpoint is synchronous, and you will receive any errors. If you are using more advanced features, generation may be asynchronous. In both cases, you can use the returned `fileExecutionId` to check the status of the delivery and retrieve the execution input, output, and metadata for the generated file. ## Transaction data The endpoint supports three ways to provide transaction data: * **No mapping or fragments**: You provide transaction data in [Guide JSON](/edi-platform/operate/transform-json/guide-json) format. The transaction data must be \< 5MB. * **Mapping**: You provide transaction data in the source schema format for the specified [Stedi mapping](/edi-platform/mappings/index). The transaction data that you want to map must be \< 4MB. * **Fragments**: You provide the fragment wrapper in [Guide JSON](/edi-platform/operate/transform-json/guide-json) format. Visit [outbound fragments](/edi-platform/fragments/outbound-fragments) for more details and examples. ## Delivery attempts Stedi attempts to deliver a file to all configured connections every 6 minutes for up to 3 total attempts. If it cannot deliver the file after the third attempt, it marks the file execution as `FAILED` and emits the [`file.failed.v2` event](/edi-platform/operate/event-types#file-failed). Stedi displays each delivery attempt and the failure details on the [Files](https://www.stedi.com/app/core/file-executions) page. ## Customize generated files You can change the timezone, time format, character set (which characters are allowed), and filename for generated files. [Learn more](/edi-platform/operate/generate-edi/index#timezone-and-time-format). ## Inbound processing There is no equivalent endpoint for parsing EDI files into JSON. To parse inbound files, you or your partner can send EDI files to an SFTP/FTPS or AS2 [connection](/edi-platform/configure/trading-partners/connections/index), and Stedi sends the JSON payload to the configured [Destination webhook](/edi-platform/configure/destinations/index). # 277CA Report healthcare get /change/medicalnetwork/reports/v2/{transactionId}/277 This endpoint retrieves processed Claim Acknowledgment (277CA) transactions from payers. * Call this endpoint with the `transactionId` of the 277CA you want to retrieve. * Stedi returns the payer's 277CA in JSON format. ## Correlate with original claim Use the following fields to correlate the 277CA with the original claim: * **Entire Claim:** The original claim's `claimInformation.patientControlNumber` is returned as the `transactions.payers.claimStatusTransactions.claimStatusDetails.patientClaimStatusDetails.claims.claimStatus.patientAccountNumber` in the 277CA. * **Service line:** The original claim's `claimInformation.serviceLines.providerControlNumber` is returned as the `transactions.payers.claimStatusTransactions.claimStatusDetails.patientClaimStatusDetails.claims.serviceLines.lineItemControlNumber` in the 277CA. However, a 277CA only contains a `serviceLines` object if it was rejected because of issues with the information provided for the service line. # 835 ERA Report healthcare get /change/medicalnetwork/reports/v2/{transactionId}/835 This endpoint retrieves processed Electronic Remittance Advice (835 ERA) transactions from payers. * Call this endpoint with the `transactionId` of the 835 ERA you want to retrieve. * Stedi returns the payer's 835 ERA in JSON format. ## Correlate with original claim Use the following fields to correlate the 835 ERA with the original claim: * **Entire claim:** The original claim's `claimInformation.patientControlNumber` is returned as the `transactions.detailInfo.paymentInfo.claimPaymentInfo.patientControlNumber` in the 835 ERA. * **Service line:** The original claim's `claimInformation.serviceLines.providerControlNumber` is returned as the `transactions.detailInfo.paymentInfo.serviceLines.lineItemControlNumber` in the 835 ERA. ## Claim status You cannot reliably determine a claim's status based on the amount paid in an 835 ERA. There are many instances in which a claim is accepted and the total amount paid is 0 dollars. For example, in Value-Based Care (VBC) scenarios, line item rates are usually 0 dollars, and providers are paid a flat rate per month or for a complete bundle of services. Instead, you can use the [Claim Status API](/api-reference/healthcare/post-healthcare-claim-status) to check the status of a claim in real-time. # List Payers healthcare get /payers This endpoint lists all of the payers Stedi supports for [eligibility checks](/api-reference/healthcare/post-healthcare-eligibility) and [claims processing](/api-reference/healthcare/post-healthcare-claims). You can use it to retrieve Payer IDs and to determine which payers require [enrollment](/healthcare/supported-payers#enrollment) before you can send transactions. You can also find a searchable list of payers in the [Payer Network](https://www.stedi.com/healthcare/network). # CMS-1500 Claim Form PDF healthcare get /export/{transactionId}/1500/pdf This is a BETA endpoint. We may make backwards incompatible changes. This endpoint retrieves the CMS-1500 Claim Form PDF that Stedi automatically generates for submitted 837 professional claims. You can also review and download the PDF from the transaction's details page in the Stedi app. # Eligibility mock requests When you submit the following requests to the [Eligibility Check](/api-reference/healthcare/post-healthcare-eligibility) endpoint, Stedi returns mock benefits data from the specified payer you can use for testing. You need a [Stedi API key](/api-reference/index#creating-an-api-key) for authentication, and you must set the `stedi-test` header to `true`. Mock requests are free for testing purposes and won't incur any charges in your Stedi account. ## Medical - Active coverage Request notes: * `encounter`: Only service type code `30` is supported. * `provider`: You can use any organization name and any NPI, as long as it passes [check digit validation](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf). To generate a dummy NPI, you can use [this free tool](https://jsfiddle.net/alexdresko/cLNB6). * `subscriber`: You must use the exact values in the test request. Other birthdates, first names, last names, and member IDs return errors. **Aetna** ```bash test request for Aetna curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "60054", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "20040404", "memberId": "AETNA12345" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Ambetter** ```bash test request for Ambetter curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "68069", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "19940404", "memberId": "AMBETTER123" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Anthem Blue Cross Blue Shield of CA** ```bash test request for Anthem BCBSCA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "040", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "19750101", "memberId": "BCBSCA123456" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Blue Cross and Blue Shield of Texas** ```bash test request for BCBSTX curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "G84980", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "20100101", "memberId": "BCBSTX123456" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Cigna** ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "James", "lastName": "Jones", "dateOfBirth": "19910202", "memberId": "23456789100" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "Rolando", "lastName": "Arrojo", "dateOfBirth": "19710102", "memberId": "5643296" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "Rod", "lastName": "Beck", "dateOfBirth": "19720203", "memberId": "R5TJR4HR4H" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "David", "lastName": "Cone", "dateOfBirth": "19730304", "memberId": "5642296" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "Frank", "lastName": "Castillo", "dateOfBirth": "19750405", "memberId": "FTRJRG3254" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "Casey", "lastName": "Fossum", "dateOfBirth": "19760506", "memberId": "5641296" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "Rich", "lastName": "Garces", "dateOfBirth": "19770607", "memberId": "DHW5445" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Humana** ```bash test request for Humana curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "61101", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19750505", "memberId": "HUMANA123" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Kaiser Permanente Northern California** ```bash test request for Kaiser Permanente curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "KSRCN", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "20020202", "memberId": "KAISER123456" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **National Centers for Medicare & Medicaid Services (CMS)** ```bash test request for CMS curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "CMS", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19550505", "memberId": "CMS12345678" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **Oscar Health** ```bash test request for Oscar Health curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "OSCAR", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "memberId": "OSCAR123456" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` **UnitedHealthcare** ```bash test request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19710101", "memberId": "UHC123456" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ## Medical - Inactive coverage **UnitedHealthcare** ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"112233445", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Provider Name", "npi": "0001112223" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19710101", "memberId": "UHCINACTIVE" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ## Dental Request notes: * `encounter`: Only service type code `35` is supported. * `provider`: You can use any organization name and any NPI, as long as it passes [check digit validation](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf). To generate a dummy NPI, you can use [this free tool](https://jsfiddle.net/alexdresko/cLNB6). * `subscriber`: You must use the exact values in the test request. Other birthdates, first names, last names, and member IDs return errors. **Ameritas** ```bash test request for Ameritas curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"164867197", "tradingPartnerServiceId": "100925", "provider": { "firstName": "Plaque", "lastName": "Penguin", "npi": "1282565121" }, "subscriber": { "firstName": "Falcon", "lastName": "Dent", "dateOfBirth": "19850607", "memberId": "007007007" }, "encounter": { "serviceTypeCodes": ["35"] } }' ``` **Anthem Blue Cross Blue Shield of CA** ```bash test request for BCBSCA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"592233731", "tradingPartnerServiceId": "84103", "provider": { "organizationName": "One", "npi": "1481480079" }, "subscriber": { "firstName": "Aardvark", "lastName": "Dent", "dateOfBirth": "19701212", "memberId": "987654321" }, "encounter": { "serviceTypeCodes": ["35"] } }' ``` **Cigna** ```bash test request for Cigna curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"590491431", "tradingPartnerServiceId": "59-1031071", "provider": { "organizationName": "One", "npi": "0001112223" }, "subscriber": { "firstName": "Jaguar", "lastName": "Dent", "dateOfBirth": "19960505", "memberId": "U3141592653" }, "encounter": { "serviceTypeCodes": ["35"] } }' ``` **Metlife** ```bash test request for Metlife curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"590555808", "tradingPartnerServiceId": "101256", "provider": { "organizationName": "One", "npi": "1231231239" }, "subscriber": { "firstName": "Elephant", "lastName": "Dent", "dateOfBirth": "19840229", "memberId": "88877788" }, "encounter": { "serviceTypeCodes": ["35"] } }' ``` **UnitedHealthcare** ```bash test request for UnitedHealthcare curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"143153149", "tradingPartnerServiceId": "52133", "provider": { "organizationName": "One", "npi": "1487885067" }, "subscriber": { "firstName": "Beaver", "lastName": "Dent", "dateOfBirth": "19690628", "memberId": "404404404" }, "encounter": { "serviceTypeCodes": ["35"] } }' ``` ## Common AAA errors The following requests return mock data for the most common Payer `AAA` errors. Visit [Eligibility troubleshooting](/healthcare/eligibility-troubleshooting) for a complete list of AAA error codes, other common eligibility check issues, and recommended resolution steps. ### 42 - Unable to respond at current time The following example request returns a `42` AAA error code, indicating that the payer is unable to respond at the current time. This is typically a temporary issue with the payer’s system, but it can also be an [extended outage](https://payer-status.stedi.com/) or the payer [throttling your requests](/healthcare/send-eligibility-checks#avoid-payer-throttling). ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "20010101", "memberId": "UHCAAA42" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ### 43 - Invalid/Missing Provider Identification The following example request returns a `43` AAA error code. This error can occur if provider's NPI is not registered with the payer, the provider's NPI is not registered *correctly* with the payer, or the payer requires an agreement. ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19700101", "memberId": "UHCAAA43" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ### 72 - Invalid/Missing Subscriber/Insured ID The following example request returns a `72` AAA error code. This error can occur if the subscriber member ID was incorrect in the request, the request does not meet the payer's requirements for the subscriber ID, or there is another unidentified error in the request data. ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "19900101", "memberId": "UHCAAA72" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ### 73 - Invalid/Missing Subscriber/Insured Name The following example request returns a `73` AAA error code. This error can occur if an incorrect subscriber name was submitted, the subscriber name was missing, the subscriber name was spelled incorrectly, or the request doesn't meet the payer's requirements for the subscriber's name. ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "19900101", "memberId": "UHCAAA73" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ### 75 - Subscriber/Insured Not Found The following example request returns a `75` AAA error code. This error occurs when the payer can't find the subscriber in their database. You should verify the subscriber details and try sending different combinations of `firstName`, `lastName`, `dateOfBirth`, and `memberId`. Note that not all search combinations are supported by all payers. ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "19900101", "memberId": "UHCAAA75" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` ### 79 - Invalid Participant Identification The following example request returns a `79` AAA error code. This error occurs when there is a problem connecting with the payer. You should contact Stedi support for assistance. ```bash request for UHC curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "87726", "provider": { "organizationName": "Medical Provider", "npi": "1122334455" }, "subscriber": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "19700101", "memberId": "UHCAAA79" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` # Real-Time Claim Status healthcare post /change/medicalnetwork/claimstatus/v2 This endpoint sends real-time 276 Claim Status requests to payers. You can use it to quickly check the status of an existing claim. * Call this endpoint with a JSON payload. * Stedi translates the JSON to the X12 276 EDI format and sends it to the payer. * The endpoint returns a synchronous response from the payer in JSON format. The response contains information about the referenced claim and its current status. ## Character restrictions Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. ## Conditional requirements Note that objects marked as **required** are required for all requests, while others are conditionally required depending on the circumstances. When you include a conditionally required object, you must include all of its required properties. For example, you must always include the `subscriber` object in your request, but you only need to include the `serviceLineInformation` object when you want to request the status for a specific service line. ## Payer limitations Payers generally only allow a provider organization to check the status of the claims they submitted. This means that you likely won't be able to check the status of a claim submitted by a different provider organization or by the patient themselves, even if you have all of the details about the claim. Payers impose these access controls to protect plan member privacy and confidential commercial data. Payers also often archive claims older than 18 months, but this varies by payer. If you try to check the status of a claim from several years ago, the payer may return an error even if the information you submit matches a real historical claim. Finally, we recommend keeping the dates of service range to 30 days or less. Some payers may reject requests with a date range that is too wide. ## Timeout Requests to payers typically time out at 1 minute, though Stedi's API can keep connections open longer than that if needed. # Real-Time Claim Status Raw X12 healthcare post /change/medicalnetwork/claimstatus/v2/raw-x12 This endpoint sends 276 Claim Status requests to payers in raw X12 EDI format. This is ideal if you have an existing system that generates X12 EDI files and you want to send them through Stedi's API. * Call this endpoint with a payload in [276 X12 EDI format](https://www.stedi.com/app/guides/view/hipaa/claim-status-request-x212/01GRYB6A4XEJQ61Y2K2KT606E5). * Stedi validates the EDI and sends the status request to the payer. * The endpoint returns a synchronous response from the payer in JSON format. The response contains information about the referenced claim and its current status. ## Character restrictions Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. ## Payer limitations Payers generally only allow a provider organization to check the status of the claims they submitted. This means that you likely won't be able to check the status of a claim submitted by a different provider organization or by the patient themselves, even if you have all of the details about the claim. Payers impose these access controls to protect plan member privacy and confidential commercial data. Payers also often archive claims older than 18 months, but this varies by payer. If you try to check the status of a claim from several years ago, the payer may return an error even if the information you submit matches a real historical claim. Finally, we recommend keeping the dates of service range to 30 days or less. Some payers may reject requests with a date range that is too wide. ## Timeout Requests to payers typically time out at 1 minute, though Stedi's API can keep connections open longer than that if needed. # Professional Claims healthcare post /change/medicalnetwork/professionalclaims/v3/submission This endpoint sends 837P (professional) claims to payers. Visit [Submit professional claims](/healthcare/submit-professional-claims) for a full how-to guide. * Call this endpoint with a JSON payload. * Stedi translates your request to the X12 837 EDI format and sends it to the payer. * The endpoint returns a response from Stedi in JSON format containing information about the claim you submitted and whether the submission was successful. ## Send test claims All claims you submit through this endpoint are sent to the payer as production claims unless you explicitly designate them as test data. To send test claims, set the `usageIndicator` field in the test claim to `T`. This allows you to filter for test claims on the [Transactions](https://www.stedi.com/app/core/transactions) page in the Stedi app. Note that you will receive a 277 Claim Acknowledgment in response to test claims, allowing you to test your workflow end to end, but you will not receive a test 835 (ERA) response. ## Basic claim submission The content of your claim submission depends on your use case and the payer's requirements. However, a basic claim submission includes the following information in the request body: | Information | Description | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tradingPartnerServiceId` | This is the Payer ID. Visit the [Payer Network](https://www.stedi.com/healthcare/network) for a complete list. | | `tradingPartnerName` | This is the payer's business name, like Cigna or Aetna. | | `submitter` object | Information about the entity submitting the healthcare claim. This can be either an individual or an organization, such as a doctor, hospital, or insurance company. | | `receiver` object | Information about the payer, such as an insurance company or government agency. | | `subscriber` and/or `dependent` objects | Information about the patient who received the medical services. Note that if a dependent has their own, unique member ID for their health plan, you should submit their information in the `subscriber` object and omit the `dependent` object from the request. You can check whether the dependent has a unique member ID by submitting an [Eligibility Check](/api-reference/healthcare/post-healthcare-eligibility) to the payer for the dependent. The payer will return the member ID in the `dependents.memberId` field, if present. | | `claimInformation` object | Information about the claim, such as the patient control number, claim charge amount, and place of service code. It also includes information about each individual service line included in the claim. | | `billing` object | Information about the billing provider, such as the NPI, taxonomy code, and organization name. | ### Character restrictions Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. ### Identify service lines A claim can contain multiple service lines. Since the payer may accept, reject, or pay a subset of those lines, you can receive an 835 response that references a `patientControlNumber`, but only pertains to some of the service lines. However, the `claimInformation.serviceLines.providerControlNumber` serves as a unique identifier for each service line in your claim submission. This value appears in the 277CA and 835 ERA responses as the `lineItemControlNumber`, allowing you to correlate these responses to specific service lines from the original claim. If you don't set the `providerControlNumber` for a service line, Stedi uses a random UUID. Stedi returns service line identifiers in the `claimReference.serviceLines` object of the synchronous API response. ## Conditional requirements Note that objects marked as **required** are required for all requests, while others are conditionally required depending on the circumstances. When you include a conditionally required object, you must include all of its required properties. For example, you must always include the `subscriber` object in your request, but you only need to include the `supervising` object when the rendering provider is supervised by a physician. ## Enhanced validation You can optionally set the `Stedi-Validation` header to `snip` for enhanced validation on your claim submission. [Enhanced validation](/healthcare/enhanced-claim-validation) uses hundreds of additional *edits* (the industry term for validation rules) to increase claim acceptance rates. These include Strategic National Implementation Process (SNIP) validations. Stedi also automatically fixes common errors and monitors payer rejections to proactively build out new rules. There is an **additional cost per claim submission** when you use enhanced validation. Please reach out to support for access and pricing information. # Professional Claims Raw X12 healthcare post /change/medicalnetwork/professionalclaims/v3/raw-x12-submission This endpoint sends 837P (professional) claims to payers in raw X12 EDI format. This is ideal if you have an existing system that generates X12 EDI files and you want to send them through Stedi's API. * Call this endpoint with a payload in [837 X12 EDI format](https://www.stedi.com/app/guides/view/hipaa/health-care-claim-professional-x222a1/01HR60MDFAGCSEJNKY8J38867Y). * Stedi validates the EDI and sends the claim to the payer. * The endpoint returns a response from Stedi in JSON format containing information about the claim you submitted and whether the submission was successful. ## Send test claims All claims you submit through this endpoint are sent to the payer as production claims unless you explicitly designate them as test data. To send test claims, set the `usageIndicator` field in the test claim to `T`. This allows you to filter for test claims on the [Transactions](https://www.stedi.com/app/core/transactions) page in the Stedi app. Note that you will receive a 277 Claim Acknowledgment in response to test claims, allowing you to test your workflow end to end, but you will not receive a test 835 (ERA) response. ## Identify service lines A claim can contain multiple service lines. Since the payer may accept, reject, or pay a subset of those lines, you can receive an 835 response that references a `patientControlNumber`, but only pertains to some of the service lines. However, the `claimInformation.serviceLines.providerControlNumber` serves as a unique identifier for each service line in your claim submission. This value appears in the 277CA and 835 ERA responses as the `lineItemControlNumber`, allowing you to correlate these responses to specific service lines from the original claim. If you don't set the `providerControlNumber` for a service line, Stedi uses a random UUID. Stedi returns service line identifiers in the `claimReference.serviceLines` object of the synchronous API response. ## Character restrictions Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. ## Enhanced validation You can optionally set the `Stedi-Validation` header to `snip` for enhanced validation on your claim submission. [Enhanced validation](/healthcare/enhanced-claim-validation) uses hundreds of additional *edits* (the industry term for validation rules) to increase claim acceptance rates. These include Strategic National Implementation Process (SNIP) validations. Stedi also automatically fixes common errors and monitors payer rejections to proactively build out new rules. There is an **additional cost per claim submission** when you use enhanced validation. Please reach out to support for access and pricing information. # Real-Time Eligibility Check healthcare post /change/medicalnetwork/eligibility/v3 This endpoint sends real-time eligibility checks to payers. Visit [Check eligibility](/healthcare/send-eligibility-checks) for a full how-to guide. * Call this endpoint with a JSON payload. * Stedi translates your request to the X12 270 EDI format and sends it to the payer. * The endpoint returns a synchronous response from the payer in both JSON and raw X12 EDI format. The response contains the patient's eligibility and benefits information. ## Test endpoint When you submit specific mock requests, Stedi returns mock benefits data from the specified payer you can use for testing. You need a [Stedi API key](/api-reference/index#creating-an-api-key) for authentication, and you must set the `stedi-test` header to `true`. Mock requests are free for testing purposes and won't incur any charges in your Stedi account. Notes: * `encounter`: Only service type code `30` is supported. * `provider`: You can use any organization name and any NPI, as long as it passes [check digit validation](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf). To generate a dummy NPI, you can use [this free tool](https://jsfiddle.net/alexdresko/cLNB6). * `subscriber`: You must use the exact values in the test request. Other birthdates, first names, last names, and member IDs return errors. ```bash test request for CIGNA curl --request POST \ --url 'https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3' \ --header 'Authorization: Key {api_key}' \ --header 'stedi-test: true' \ --header 'Content-Type: application/json' \ --data '{ "controlNumber":"123456789", "tradingPartnerServiceId": "62308", "provider": { "organizationName": "Provider Name", "npi": "0123456789" }, "subscriber": { "firstName": "James", "lastName": "Jones", "dateOfBirth": "19910202", "memberId": "23456789100" }, "encounter": { "serviceTypeCodes": ["30"] } }' ``` Visit [Send mock requests](/api-reference/healthcare/mock-requests-eligibility-checks) for additional mock requests. ## Basic eligibility check The content of your eligibility request depends on your use case and the payer's requirements. However, a basic eligibility check includes the following information in the request body: | Information | Description | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `controlNumber` | An integer used to identify the transaction. It does not need to be globally unique. This value is returned in the response as `controlNumber`. | | `tradingPartnerServiceId` | You can find the payer ID in our list of [supported payers](https://www.stedi.com/healthcare/network). | | `provider` object, name | You must include the provider's name - either the `firstName` and `lastName` of a specific provider within a practice or the `organizationName`. | | `provider` object, identifier | You must include an identifier. Most often this is the National Provider Identifier (NPI). The [NPI](https://www.cms.gov/Regulations-and-Guidance/Administrative-Simplification/NationalProvIdentStand) is a unique, 10-digit identification number assigned to healthcare providers according to HIPAA standards. | | `subscriber` and/or `dependents` objects | At a minimum, our API requires that you supply at least one of these fields in the request: `memberId`, `dateOfBirth`, or `lastName`. However, each payer has different requirements, so you should supply the fields necessary for each payer to identify the subscriber in their system. When all four of `memberId`, `dateOfBirth`, `firstName`, and `lastName` are provided, payers are required to return a response if the member is in their database. Some payers may be able to search with less information, but this varies by payer. We recommend always including the patient's member ID when possible. Learn more about [patient information](/healthcare/send-eligibility-checks#patient-information). | | `encounter` object, service dates | You can specify either a single `dateOfService` or a `beginningDateOfService` and `endDateOfService`. The payer defaults to using the current date in their timezone if you don't include one. We recommend submitting dates up to 12 months in the past or up to the end of the current month. Dates outside of these ranges are likely to be rejected by many payers, since they may have archived older data and they cannot guarantee eligibility for future months. | | `encounter` object, service or procedure codes | Specify `serviceTypeCodes` and/or a `procedureCode` and `productOrServiceIDQualifier` to request specific types of benefits information. We don't know which payers support multiple service type codes, so we recommend including no more than one in each request. If you do not include any of these fields, Stedi defaults to using `30` (Plan coverage and general benefits) as the only `serviceTypeCodes` value. Learn more about [checking eligibility for specific services](/healthcare/send-eligibility-checks#checking-eligibility-for-specific-services). | ## Character restrictions and replacement Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. Stedi automatically replaces backticks (`` ` ``), also known as backquotes or grave accents, with a single quote (`'`) in `subscriber` and `dependents` first and last names. This autocorrection prevents errors when submitting your request to payers and intermediary clearinghouses. Stedi returns a message in the response's `warnings` array when it makes this replacement. ## Conditional requirements Note that objects marked as **required** are required for all requests, while others are conditionally required depending on the circumstances. When you include a conditionally required object, you must include all of its required properties. For example, you must always include the `provider` object in your request, but you only need to include the `informationReceiverName` object when you need to include additional information about the provider making the request, such as their specific location. ## Timeout and Concurrency Requests to payers typically time out at 1 minute, though Stedi can keep connections open longer than that if needed. Our real-time eligibility check endpoint has rate limiting on a per-account basis. This limit is based on *concurrent* requests, not requests per second. The default rate limit is 5 concurrent requests; if you need a higher limit, reach out to [Support](https://www.stedi.com/contact). Insurance payers may take up to 60 seconds to respond to a request, so your transactions per second (and thus your concurrency limit) will vary based on the payer response time. If you reach the maximum concurrency limit, Stedi rejects additional requests with a `429` HTTP code until one of your previous requests is completed. Rejected requests have the following error message: ``` { "message": "The request can't be submitted because the sender's submission has been throttled: CUSTOMER_LIMIT", "code": "TOO_MANY_REQUESTS", "eligibilitySearchId": "019249c7-e176-76b0-a46a-3aef1a519bc4" } ``` ## Benefit response Visit [Payer benefit response](https://www.stedi.com/docs/healthcare/benefit-response) for definitions of key benefit types and information about how to interpret benefits requirements such as prior authorization and referrals. **Network status:** The response provides information about the patient's general in and out-of-network coverage. It does not confirm whether a particular provider is in or out-of-network. To determine network status, you must check directly with the payer. Note that payers may have different networks for different health plans, such as employer-sponsored plans versus Medicare. ## Troubleshooting For a list of possible errors and resolution steps, visit [Errors and resolutions](/healthcare/eligibility-troubleshooting). # Real-Time Eligibility Check Raw X12 healthcare post /change/medicalnetwork/eligibility/v3/raw-x12 This endpoint sends real-time eligibility checks to payers in raw X12 EDI format. This is ideal if you have an existing system that generates X12 EDI files and you want to send them through Stedi's API. * Call this endpoint with payload in [270 X12 EDI format](https://www.stedi.com/app/guides/view/hipaa/health-care-eligibility-benefit-inquiry-x279a1/01GRYB6GTDJ4MEP5Z16CGMQWT6). * Stedi validates the EDI and sends the eligibility check to the payer. * The endpoint returns a synchronous response from the payer in both JSON and raw X12 EDI format. The response contains the patient's eligibility and benefits information. ## Character restrictions and replacement Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. Stedi automatically replaces backticks (`` ` ``), also known as backquotes or grave accents, with a single quote (`'`) in `subscriber` and `dependents` first and last names. This autocorrection prevents errors when submitting your request to payers and intermediary clearinghouses. Stedi returns a message in the response's `warnings` array when it makes this replacement. ## Timeout and Concurrency Requests to payers typically time out at 1 minute, though Stedi can keep connections open longer than that if needed. Our real-time eligibility check endpoint has rate limiting on a per-account basis. This limit is based on *concurrent* requests, not requests per second. The default rate limit is 5 concurrent requests; if you need a higher limit, reach out to [Support](https://www.stedi.com/contact). Insurance payers may take up to 60 seconds to respond to a request, so your transactions per second (and thus your concurrency limit) will vary based on the payer response time. If you reach the maximum concurrency limit, Stedi rejects additional requests with a `429` HTTP code until one of your previous requests is completed. Rejected requests have the following error message: ``` { "message": "The request can't be submitted because the sender's submission has been throttled: CUSTOMER_LIMIT", "code": "TOO_MANY_REQUESTS", "eligibilitySearchId": "019249c7-e176-76b0-a46a-3aef1a519bc4" } ``` ## Benefit response Visit [Payer benefit response](https://www.stedi.com/docs/healthcare/benefit-response) for definitions of key benefit types and information about how to interpret benefits requirements such as prior authorization and referrals. **Network status:** The response provides information about the patient's general in and out-of-network coverage. It does not confirm whether a particular provider is in or out-of-network. To determine network status, you must check directly with the payer. Note that payers may have different networks for different health plans, such as employer-sponsored plans versus Medicare. ## Troubleshooting For a list of possible errors and resolution steps, visit [Errors and resolutions](/healthcare/eligibility-troubleshooting). # Institutional Claims healthcare post /change/medicalnetwork/institutionalclaims/v1/submission This is a BETA endpoint. We may make backwards incompatible changes. This endpoint sends 837I (institutional) claims to payers. * Call this endpoint with a JSON payload. * Stedi translates your request to the X12 837 EDI format and sends it to the payer. * The endpoint returns a response from Stedi in JSON format containing information about the claim you submitted and whether the submission was successful. ## Send test claims All claims you submit through this endpoint are sent to the payer as production claims unless you explicitly designate them as test data. To send test claims, set the `usageIndicator` field in the test claim to `T`. This allows you to filter for test claims on the [Transactions](https://www.stedi.com/app/core/transactions) page in the Stedi app. Note that you will receive a 277 Claim Acknowledgment in response to test claims, allowing you to test your workflow end to end, but you will not receive a test 835 (ERA) response. ## Basic claim submission The content of your claim submission depends on your use case and the payer's requirements. However, a basic claim submission includes the following information in the request body: | Information | Description | | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | | `tradingPartnerServiceId` | This is the Payer ID. Visit the [Payer Network](https://www.stedi.com/healthcare/network) for a complete list. | | | `submitter` object | Information about the entity submitting the healthcare claim. This is an organization, such as a hospital or other treatment center. | | | `receiver` object | Information about the entity responsible for the payment of the claim, such as an insurance company or government agency. | | | `subscriber` and/or `dependent` objects | Information about the patient who received the medical services. Note that if a dependent has their own, unique member ID for their health plan, you should submit their information in the `subscriber` object and omit the `dependent` object from the request. You can check whether the dependent has a unique member ID by submitting an [Eligibility Check](/api-reference/healthcare/post-healthcare-eligibility) to the payer for the dependent. The payer will return the member ID in the `dependents.memberId` field, if present. | | | `claimInformation` object | Information about the claim, such as the claim filing code (identifies the type of claim), claim charge amount, and place of service code. It also includes information about each individual service line included in the claim. | | | Billing provider | You **must** supply information about the billing provider in either the `providers` or `billing` object. This includes the provider's NPI, name, and other information. | | ### Character restrictions Don't include the following characters in your request data: `~`, `*`, `:` and `^`. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a `400` error if you include these restricted characters in your request. ### Identify service lines A claim can contain multiple service lines. Since the payer may accept, reject, or pay a subset of those lines, you can receive an 835 response that references a `patientControlNumber`, but only pertains to some of the service lines. However, the `claimInformation.serviceLines.lineItemControlNumber` serves as a unique identifier for each service line in your claim submission. This value appears in the 277CA and 835 ERA responses as the `lineItemControlNumber`, allowing you to correlate these responses to specific service lines from the original claim. We strongly recommend setting the `lineItemControlNumber` to a ULID or other unique identifier for each service line. We recommend using a ULID instead of a UUID because the property has a max of 30 characters. ## Conditional requirements Note that objects marked as **required** are required for all requests, while others are conditionally required depending on the circumstances. When you include a conditionally required object, you must include all of its required properties. For example, you must always include the `subscriber` object in your request, but you only need to include the `supervising` object when the rendering provider is supervised by a physician. # API Reference Download our OpenAPI specs Healthcare APIs EDI Platform APIs ## Healthcare APIs Our APIs allow you to automate business flows like [eligibility checks](/api-reference/healthcare/post-healthcare-eligibility) and [claims processing](/api-reference/healthcare/post-healthcare-claims). They're also designed to be compatible with Change Healthcare (CHC) request and response payloads so existing CHC customers can switch to Stedi without code changes. ## EDI platform APIs You can programmatically accomplish almost anything you can do in the Stedi app. In practice, most integrations only need to implement two integration points: * A method in your system for calling the [Create Outbound Transaction](/api-reference/edi-platform/post-transactions) endpoint when you need to send a transaction **to** a trading partner * A method in your system for receiving [destination webhooks](/edi-platform/configure/destinations) from Stedi when you receive a transaction **from** a trading partner, or when an exception occurs. ## Authentication You need an API key to use any Stedi API. You pass the API key in the `Authorization` header of every request and Stedi determines which resources you can access. ### Creating an API key To create an API key: 1. Log into your [Stedi account](https://www.stedi.com/app). 2. Click your account name at the top right of the screen. 3. Select **API Keys**. 4. Click **Generate API Key**. 5. Enter a description and click **Generate**. Stedi generates an API key and allows you to copy it. {' '} Make sure you copy your API key and store it in a safe location. Once you close the modal, Stedi will not show the API key again. ### API key access In accounts on an Essentials plan, an API key grants access to all resources belonging to an account. In accounts on an Enterprise plan, members can be [assigned to roles](/accounts-and-billing/index#assigning-member-roles) with different permissions. API keys inherit the permissions of the account member who created them and keep those permissions even if the creator's role is later updated. ### Passing the API key Every request you send needs to include an API key. You pass the API key in the `Authorization` header. For example, if your API key is `Jclcke.ZHqS3demo4dS16XZ1KeyBY7`, you would insert it into the header according to the following example: ```bash curl --request POST \ --url https://core.us.stedi.com/2023-08-01/x12/partnerships/{partnershipId}/generate-edi \ --header 'Authorization: Jclcke.ZHqS3demo4dS16XZ1KeyBY7' \ --header 'Content-Type: application/json' \ --data '{ ... }' ``` Stedi supports the previous method of prefixing the API key with `Key` (e.g. `Authorization: Key Jclcke.ZHqS3demo4dS16XZ1KeyBY7`) for backwards-compatibility. ## Pagination When you request a list of resources, the response may contain a subset of available responses. In that case, the response will include a key called `next_page_token`. To retrieve the next page of results, repeat the request, but add the query parameter `page_token` and give it the value you received in the response. For example, when you call the [List Transactions API](/api-reference/edi-platform/core/get-list-transactions), the result contains a list of every transaction within your Stedi account and a token for the next page. ```javascript { "items": [ ... ], "next_page_token": "2t7M75ZN1w4OnYFKKT0SUkT95w_ULzPR" } ``` You can then request the next page of results like this: ```bash curl --request GET \ --url https://core.us.stedi.com/2023-08-01/transactions?page_token=2t7M75ZN1w4OnYFKKT0SUkT95w_ULzPR \ --header "Authorization: ${STEDI_API_KEY}" ``` As long as the response contains `next_page_token`, there are more results available. If a response doesn't contain `next_page_token`, then you're on the last page. ## Error Responses If you make a request that the API can't fulfill, the response code will be in the 4xx range and the response body will contain the following two fields. * `error` – A code indicating what went wrong. * `message` – A human-readable message describing what went wrong. You can use `error` to write code that handles the error and you can use `message` when you're debugging the problem yourself. If a response needs to report multiple errors, it will include an array called `errors`, but even in that case, the `error` and `message` fields will be available at top level. It's possible for a response to contain both a result and an error. This happens when something went wrong, but the API is able to give a partial or best-effort result. ## Idempotency keys Idempotency allows you to make an API request multiple times without causing different outcomes. Adding idempotency keys to requests can prevent sending duplicate data to your trading partners in the case of network errors or other intermittent failures. You can safely retry requests with the same idempotency key as many times as necessary within 24 hours after making the first request. Within the 24 hour period, if you reuse the same key with different request contents (change the HTTP method, path, or request body), Stedi returns a `422 Unprocessable Entity` error. After 24 hours, Stedi allows the request to execute again even if you submit the same idempotency token. ### Generating keys For APIs that support idempotency, you can generate and include an idempotency key within the `Idempotency-Key` header of your request. Our implementation conforms to the draft IETF [Idempotency-Key HTTP Header Field](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/) RFC. The token can be any unique string, such as a UUID. Common approaches to generating tokens are: * Use an algorithm that generates a token with enough randomness, like UUID v4. * Derive the key from data related to the API call, like a partnership ID and a transaction number. This approach helps you prevent duplicate requests for the same partnership and request type. ### Adding keys to your request Once you have generated your idempotency key, include it in the header of your API request. For example, the header for a request to the [Create Outbound Interchange API](/api-reference/edi-platform/post-generate-edi) would look like this: ```bash curl --request POST \ --url https://core.us.stedi.com/2023-08-01/x12/partnerships/{partnershipId}/generate-edi \ --header 'Authorization: ${STEDI_API_KEY}' \ --header 'Idempotency-Key: 5b6f6d3e-2c6d-4e6f-8e6f-6d3e2c6d4e6f' \ --header 'Content-Type: application/json' \ --data '{ ... }' ``` ## API upgrades We strive to maintain backwards compatibility. The following changes are considered backwards compatible: * New API resources * Additional optional parameters to API requests * Additional fields in API responses * Changes in the order of properties in API responses * Changes in human-readable error messages * Downgrading mandatory parameters to optional parameters. When we introduce a breaking change, we release a root-level, dated version. # Configure destinations Destinations is a legacy feature. It is not deprecated, but it has been superseded by [Webhooks](/edi-platform/configure/webhooks/index). Please [contact support](https://www.stedi.com/contact) with questions. To configure a destination webhook, you must first create an [auth](#auth), then one or more [destinations](#destination) for the auth, and then one or more [event bindings](#event-bindings) that trigger each destination. You may want to configure webhooks to: * Send processed transaction data to an external system. You can optionally attach a Stedi mapping to transform the payload before sending it to the destination. We recommend only using a mapping with a destination when you know your mapping output will be under 1MB in size. Otherwise, you can use the [Map Transaction Output](/api-reference/edi-platform/get-map-transaction-output) endpoint to retrieve mapped data asynchronously. * Send Stedi events to systems like Slack and PagerDuty or to implement more advanced functionality. ## Auth An auth defines how to authenticate with a specific API. You can use a single auth configuration across multiple destinations. Stedi supports the following types of auth configurations. | Type | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | API Keys | The API keys as headers in the request. The most common version is ‘bearer tokens’. | | Basic Auth | [HTTP Basic Auth](https://developer.mozilla.org/en-US/Web/HTTP/Authentication), where you provide a username and password. | | OAuth 2.0 | [OAuth 2.0 Auth](https://oauth.net/2/), where you can set the Authorization endpoint and parameters, the HTTP method, a client ID, and a client secret. | ### Unauthenticated endpoints There isn't a 'no-auth' option with Destinations, but you can achieve this by configuring the API Keys auth to use arbitrary values for `Header name` and `Value` (e.g. `Header name: x-stedi-noauth` and `Value: dummy`). Since the receiving API isn't authenticating the call, it will ignore these values and accept the request. ### Create auth To create a new auth: 1. Go to the [Destinations](https://www.stedi.com/app/events/destinations) page. 2. Click **Add new auth**. 3. Enter a name for the auth. 4. Choose the appropriate **Authentication type**. 5. Enter the details for the auth. 6. Click **Done**. ## Destination The destination defines which URL endpoint should be called when the destination is invoked, and which HTTP method to use (`POST`, `PUT`, `GET`, `PATCH`, `DELETE`). Destinations are scoped to a single auth. However, you might have multiple destinations for a single system integration, each with a different endpoint. For example, one endpoint for creating Sales Orders and another for Item Fulfillments. ### Create destination To create a new destination: 1. Go to the [Destinations](https://www.stedi.com/app/events/destinations) page. 2. Under the desired auth, click **Add destination**. 3. Enter a name. 4. Choose a **Method** and enter an **Endpoint**. 5. (Optional) Enter a **Max executions per second**. Use this to avoid overloading the target service. ## Event bindings Event bindings allow you to specify which events trigger the destination webhook. You can create multiple event bindings for a single destination. For example, you may want to create an event binding for each type of transaction you want to send to your API. ### Create event binding To create a new event binding: 1. Go to the [Destinations](https://www.stedi.com/app/events/destinations) page. 2. Click the desired destination. 3. Click the **Edit** tab. 4. Click **Add event binding**. 5. Choose an **Event detail-type** and complete the remaining fields. 6. (Optional) Select a mapping to transform the payload before sending it to the destination. This is only available for `transaction.processed.v2` and `fragment.processed.v2` events. 7. Click **Create binding**. ## Send transaction data You can create a `transaction.processed.v2` event binding to send processed transaction data to external APIs. If the transaction set uses [fragments](/edi-platform/fragments) to split the payload into smaller chunks, you can also configure an event binding for `fragment.processed.v2` events. You can optionally add a Stedi mapping to both types of event bindings to transform the payload shape before sending it to the destination. ### Event types Stedi emits a `transaction.processed.v2` event each time it processes a transaction. An EDI file can contain multiple transactions, so a single EDI file can produce multiple events that each invoke the configured destination webhook. When you use a `transaction.processed.v2` event to trigger a destination, Stedi includes the [Guide JSON](/edi-platform/operate/transform-json/guide-json) transaction in the payload along with the event data. The transaction itself is only included as part of the event if the whole response (payload + event) is \< 1MB. Otherwise, the event will contain a section that specifies the transaction was too big to be included and you can retrieve the actual transaction by making a request to the `transaction` artifact. When [fragments](/edi-platform/fragments) are enabled, the `transaction.processed.v2` payload includes an empty array in place of the fragmented segment. Stedi then emits one `fragment.processed.v2` event for each fragment within the processed transaction. The event contains a link you can use to retrieve the fragment data as well as information about the original transaction, such as the ISA and GS headers. Refer to [Events](/edi-platform/operate/event-types) for complete details and examples. ### Configure event bindings Choose `transaction.processed.v2` or `fragment.processed.v2` as the **Event detail-type** and complete the following fields: 1. (Optional) Choose a **Transaction set ID**. This is useful if you want to send different transaction sets to different endpoints. For example, you could send 850 Purchase Orders to one endpoint and 860 Purchase Order Change Requests to another. 2. (Optional) Choose a **Partnership ID**. This is useful if you want to send transactions from different partners to different endpoints. For example, you could send transactions from Walmart to one endpoint and transactions from Target to another. This is less common. 3. (Optional) Select a **Guide**. This is useful if you want to send transactions parsed using different guides to different endpoints. For example, you may receive `005010` 850 Purchase Orders from two different retailers, and those retailers have different guides. Since the transaction payloads will differ, you may want to send them to different API endpoints within your system. 4. (Optional) You can configure the following **Advanced** settings: * **Connection:** This is useful when you are using multiple connections for a single partnership. For example, you may have set up one connection type for test data and a separate connection for production data. * **Mode:** Specify the type of data Stedi is sending to the destination. You can choose from **Test** or **Production**. 5. (Optional) Select a **Guide** + **Mapping**. This is useful if you want to send transactions parsed using different guides to the same endpoint. For example, you may receive `005010` 850 Purchase Orders from two different retailers, and those retailers have different guides. Since the transaction payloads will differ, you can [choose a mapping](#transform-data-with-mappings) to convert the 850s to your API shape. {" "} If you plan to [add a mapping](#transform-data-with-mappings) to this event binding, you must select a guide. When you add a mapping, you are only able to select a mapping that uses the same guide as a `source`. ## Transform data with mappings Stedi integrations use [Guide JSON](/edi-platform/operate/transform-json/guide-json), a JSON format that closely reflects the structure of an EDI transaction. You may need to reshape transaction data from Guide JSON format into the shape required for the target API. For example, you may need to rename fields, add or remove fields, or change the data type of a field. You can use the [Mappings module](/edi-platform/mappings/index) to transform your payload into the required shape before sending it to a destination. ### Size limits Two size limits must be met for Stedi to both deliver the event and include the transaction data in the event payload. 1. The enriched event must be less than 4 MB when Stedi passes it to the mapping. 2. The mapping output must be under 1MB. ![Destination and mappings size limits](https://mintlify.s3-us-west-1.amazonaws.com/stediinc/images/events/size-limits.svg) If either of these size limits fails, Stedi considers the event delivery a failure and adds the event to the destination's error queue. Instead, you can: * Use [fragments](/edi-platform/fragments) to split the transaction payload into smaller chunks before sending it to a destination. * Use the [Map Transaction Output](/api-reference/edi-platform/get-map-transaction-output) endpoint to retrieve processed, mapped transaction data from Stedi. ### Add a Stedi mapping This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. To add a mapping: 1. Use the [mappings editor](https://www.stedi.com/app/mappings) to create a transformation for the event. You must choose the event when creating the source schema. Refer to the [mappings documentation](/edi-platform/mappings/manage-mappings/ui-guide) for instructions. 2. Select the mapping in the **Mapping** menu when creating your event binding. You will only be able to select mappings that use the same guide you selected in the event binding. Stedi will apply the mapping to the event data before sending it to the destination. # Destinations error handling and limitations Destinations is a legacy feature. It is not deprecated, but it has been superseded by [Webhooks](/edi-platform/configure/webhooks/index). Please [contact support](https://www.stedi.com/contact) with questions. [Destination webhooks](/edi-platform/configure/destinations/configure-destinations) allow you to send data from Stedi to third-party services without writing any custom code. ## Limitations Destinations has certain limitations. If your system's API has different requirements, you can set the destination target to be: * A function, such as AWS Lambda, Google Cloud Functions, or Azure Functions, which can then call the third-party API * An iPaaS platform, such as Zapier or Workato, which can then call the third-party API. ## HTTP response codes Stedi considers a 2xx response a success, and marks any other response as a failure. Stedi retries events associated with status codes other than `2xx` for up to 5 hours. In the event of an error response (after the retry period), Stedi adds the event to the [error queue](#error-queue) for the destination. To prevent throttling, you can set a **Max executions per second** when [configuring the destination](/edi-platform/configure/destinations/configure-destinations#create-destination). ## Response time The target endpoint must respond within 5 seconds, or the event will be counted as a failed delivery. ## Retries When a destination delivery fails, Stedi will retry up to 5 times every 90 seconds. After the fifth retry, Stedi moves the event to the error queue. ## Error queue Each destination includes an error queue. Each item in the queue consists of the original event that was attempted to be delivered. This ensures if the target service has some downtime, or anything else goes wrong, the missed events can be retried later. The error queue retains items for 14 days. Viewing the HTTP response from the third-party service is not currently supported. The order of the error queue is not guaranteed. The downstream service must be designed to be idempotent to handle at-least-once delivery of events, and must accept events out of order. ## Logs To view logs, click the Destination to go to its detail page, and then navigate to the **Logs** tab. ## Deauthorized connections If a destination sends a message to an endpoint that returns a 401 (Unauthorized) response, or the OAuth endpoint returns an error, the destination will be 'deauthorized'. In this state, the destination won't be able to deliver messages. If there is an issue with your authentication information (such as the password, API key, or OAuth settings), edit the destination to fix it. If the authentication information is correct, and there was a different reason for the endpoint returning a 401, you can try again by adding a temporary header. Edit the destination, and under the advanced toggle, add any header and value. For example, `x-stedi-reauthorize` with today's date as a value. When you save, the destination will attempt to deliver again. This header can be removed later. Editing the value of a header will also restart deliveries. You will likely have a queue of messages to deliver, so after making this change they will start automatically being retried. If the endpoint is still returning an invalid response, the destination will return to `Deauthorized` # Destinations overview Destinations is a legacy feature. It is not deprecated, but it has been superseded by [Webhooks](/edi-platform/configure/webhooks/index). Please [contact support](https://www.stedi.com/contact) with questions. Each time you receive an EDI file from a trading partner, you will want to send the included transactions to your downstream system for processing. You can do this by configuring a Destination webhook. Destination webhooks allow you to send data from Stedi to third-party services without writing any custom code. The most common use case is sending processed transaction data to your internal systems and business applications. You can also configure webhooks for other [Stedi events](/edi-platform/operate/event-types), like when a processing error occurs. This can be used to trigger alerts in systems like Slack, PagerDuty, or Zendesk for further review. Stedi can send webhooks to: * Custom applications using Basic, OAuth, or API Key authorization * Cloud functions, including AWS Lambda, Google Cloud Functions, and Azure Functions * iPaaS platforms, such as Zapier, Workato, or Tray.io * ERPs like NetSuite, SAP, or Oracle. # EDI settings You can configure the following behavior from the [EDI Settings](https://www.stedi.com/app/core/settings) page. These settings apply to every partnership in your Stedi account. ## Inbound AS2 You can enable Inbound AS2 if you need to receive files from trading partners using an [AS2 connection](/edi-platform/configure/trading-partners/connections/as2). This isn't necessary if you are only sending outbound files over AS2. ## Inbound processing concurrency Inbound processing concurrency lets you configure the number of inbound files Stedi processes at once. The concurrency limit applies across all partnerships within your Stedi account. The default inbound concurrency limit is 25 files. If you need to process more files at once, [contact us](https://www.stedi.com/contact), and we can increase the limit for your account. ## Remote SFTP/FTPS static IP address Enabling a static IP address ensures that your [Remote SFTP/FTPS connections](/edi-platform/configure/trading-partners/connections/remote-ftp) always use the same source IP address when communicating with remote servers. You can share this IP address with partners who require this additional level of access control. If your partners don’t require a static IP address, we recommend leaving this setting as disabled. ## Automatic data removal This functionality is available for Enterprise accounts. [Contact us](https://www.stedi.com/contact) for details. Artifacts refer to the transaction and file execution payloads from files Stedi has processed. They contain the actual input/output transaction data in EDI, JSON, or another format. Artifacts do not include the metadata about a transaction or file execution, such as whether it was processed successfully. You may want Stedi to remove artifacts after a certain timeframe - for example, to comply with your company's PII/PHI retention policies. You can configure the artifact retention period in **Automatic data removal**. Once you set a retention period, Stedi deletes artifacts after the retention window has passed. **This affects both existing and future data in your account.** For example, if you set a retention period of 30 days and process a file today, Stedi will delete the artifact after 30 total days have elapsed. Stedi will also delete any artifact that was created more than 30 days prior. **Stedi deletes historical files outside the retention window immediately upon configuring the retention period.** In this example, Stedi would not delete an artifact that was processed less than 30 days prior. You cannot recover deleted artifacts. # Configuration overview You need the following configuration for each new trading partner. ![Inbound and Outbound file processing flow](https://mintlify.s3-us-west-1.amazonaws.com/stediinc/images/diagrams/stedi-flow.svg) ## Partnership A [partnership](/edi-platform/configure/trading-partners/profiles-and-partnerships) defines the EDI relationship between you and your trading partner. Inside your partnership, you'll define all of the configuration specific to exchanging files with your partner, including the connection protocol, transaction settings, whether to send automatic acknowledgments, and more. ## Connection A [connection](/edi-platform/configure/trading-partners/connections/index) configures the protocol you'll use to exchange files with your partner. This can be SFTP/FTPS or AS2. Stedi automatically processes inbound files your partner sends over the connection. When you call Stedi's API to generate an outbound EDI file, Stedi automatically delivers it to your partner through the connection you configure for the partnership. ## Transaction settings You'll create a [transaction setting](/edi-platform/configure/trading-partners/transaction-settings) for each EDI transaction type you plan to send or receive. Transaction settings tell Stedi which [guide](/edi-platform/guides) (EDI requirements) to use for the transaction type. * For inbound transactions, Stedi uses the attached guide to validate and translate the EDI into JSON. * For outbound transactions, Stedi uses the guide to validate the JSON payload you submit to the API and then generate a fully-formed EDI file. ## Webhooks [Webhooks](/edi-platform/configure/webhooks/index) are one of the most important integration points with the Stedi platform. They allow you to automatically send events from Stedi to any external API. You'll configure at least one webhook to send `transaction.processed.v2` events to your business system. Then, you can programatically retrieve the processed transaction data from Stedi. # Message Disposition Notifications (MDNs) AS2 supports MDN (message disposition notification), a way for your partner to acknowledge that they have received your message. Some partners may require that you request and accept an MDN response, send MDN responses, or both. ## What is an MDN? An MDN (Message Disposition Notification) serves as a receipt to acknowledge that a message has been received and can verify various aspects of the message's integrity and authenticity. You or your trading partners may request MDNs for the following reasons: * **Acknowledge receipt:** An MDN serves as a verifiable acknowledgment that a message has been received by the trading partner's system. * **Security**: If the sent message was signed, the MDN allows the sender to confirm that the receiving system has authenticated the sender and verified the message's integrity. * **Non-Repudiation:** MDNs provide evidence that a message has been both received and processed, which can be essential in dispute resolution or auditing scenarios. According the AS2 specification, MDNs can either be synchronous (provided on the same connection as the HTTP request) or asynchronous (sent separately after the initial HTTP request), depending on the requirements of a given partnership. ## Configure MDNs For outbound messages, Stedi only supports accepting synchronous MDNs, so you need to tell your partner to send synchronous MDNs if they wish to send an MDN response. Visit [Requirements](/edi-platform/configure/trading-partners/connections/as2/as2-requirements#with-an-mdn-response-requested) for configuration details. For inbound messages, Stedi automatically sends MDNs when requested. Stedi delivers MDNs either asynchronously or synchronously, depending on the specified parameters in your partner’s request. Visit [Requirements](/edi-platform/configure/trading-partners/connections/as2/as2-requirements#with-an-mdn-response-returned) for configuration details. ## View MDN responses To view the MDN response associated with a file: 1. Go to the [Files](https://www.stedi.com/app/core/file-executions) page and click the file to view its details. 2. Click **Connection deliveries**. 3. Under **MDN Status** click **View file**. You can review the contents of the MDN response and optionally download it to your machine. # AS2 Connections The AS2 protocol is a popular protocol for securely exchanging EDI files. Stedi provides fully-managed AS2 connections that take care of the intricacies of AS2 and scale automatically to meet your demand. ## About AS2 You can technically use AS2 to exchange any type of file, but it is not commonly used outside of EDI. AS2 and its predecessor, AS1, were designed to facilitate the secure exchange of business transactions using digital certificates and encryption prior to the popularization of HTTPS. AS2 was formalized in 2005 by the Internet Engineering Task Force (IETF) in [RFC 4130](https://www.rfc-editor.org/rfc/rfc4130). Despite the fact that HTTPS is now the de facto standard for secure message exchange, AS2 is still widely used throughout the business world. Modern AS2 connections, including those in the Stedi platform, can use both HTTP and HTTPS as the underlying transport protocol. The requirements for AS2 setup differ depending on whether you use HTTP or HTTPS. Setting up an AS2 connection with a partner involves generating one or more public-private key pairs for use in encrypting and signing messages. Your partner will also need to generate their own key pairs, and then you and your partner will need to exchange public keys and agree upon an encryption algorithm. ## View connection logs You can view and filter logs for each AS2 connection. You can view three types of logs: * **Provisioning:** These logs detail each step to create or update the connection, such as provisioning the certificates, making it easier to diagnose errors. * **Inbound:** These logs detail each file that your partner sends to you over the connection. * **Outbound:** These logs detail each file that you generate and send to your partner over the connection. To view logs, go to the partnership associated with the connection and click the connection to view its details page. ## Known limitations * Server-side TCP keep-alive is not supported. The connection times out after 350 seconds of inactivity unless the client sends keep-alive packets. * If an inbound message does not contain valid AS2 headers, it will not appear in the logs. * Multiple attachments and certificate exchange messaging (CEM) from AS2 version 1.2 are not currently supported. * For outbound messages, your partner's server must support the Cryptographic Message Syntax (CMS) algorithm protection attribute for validating message signatures, as defined in [RFC 6211](https://www.rfc-editor.org/rfc/rfc6211). This is not supported in certain older IBM Sterling products. * For outbound messages over HTTPS, your partner's endpoint must support the TLS version 1.2 protocol and one of the following cryptographic algorithms: * `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256` * `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` * `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384` * `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` * `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` * `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` * `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384` * `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` * `TLS_RSA_WITH_AES_128_CBC_SHA256` * `TLS_RSA_WITH_AES_256_CBC_SHA256` # AS2 requirements There is certain base-level information that you will always need to exchange with your partner prior to setting up an AS2 connection: | Item | Usage | | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------- | | Your partner's AS2 ID | Required | | [Your AS2 ID](/edi-platform/configure/trading-partners/connections/as2/configure-as2#choose-your-as2-identifier) | Required | | Your partner's AS2 server URL | Required if sending AS2 messages | | [Your AS2 server URL](https://www.stedi.com/app/core/settings) | Required if receiving AS2 messages | The rest of the information you need to exchange with your partner depends on the scenario(s) you want to support, and your partner's requirements. The following scenarios help you understand how AS2 works and how you can use it to exchange transactions with your trading partners. ## Send AS2 messages to a partner For outbound AS2 messages, the configuration requirements differ depending on several factors: * Whether your partner's server uses HTTP or HTTPS * Whether your partner requires you to sign your messages * Whether your partner requires you to accept an MDN response ### Using HTTP without encryption If your partner's server URL starts with `http://`, Stedi will send messages to your partner using standard HTTP. Since HTTP does not support encryption natively, Stedi must encrypt your messages according to the AS2 protocol before sending them to your partner. The following table shows the configuration information you need to send AS2 messages to a partner over HTTP. | Item | Usage | Comments | | -------------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | | Your partner's public encryption certificate | Required | | | Your partner's encryption algorithm | Required | Must be `AES128_CBC`, `AES192_CBC`, or `AES256_CBC` | | Your partner's certificate chain | Optional | Required if your partner certificate was issued by a third-party Certificate Authority (CA) | | Your public encryption certificate | Not used | | | Your private encryption key | Not used | | In this scenario, Stedi uses your partner's public encryption certificate and specified encryption algorithm to encrypt the message. Stedi then sends the encrypted message to your partner's server over HTTP, and your partner uses their private key to decrypt the message. ### Using HTTPS without signing If your partner's server URL starts with `https://`, Stedi will send messages to your partner using HTTPS. Data transferred over HTTPS is natively encrypted, but some partners may also require you to encrypt the payload using AS2. The following table shows the information you need to send AS2 messages to a partner over HTTP. | Item | Usage | Comments | | -------------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | | Your partner's public encryption certificate | Optional | | | Your partner's encryption algorithm | Optional | If used, must be `AES128_CBC`, `AES192_CBC`, or `AES256_CBC` | | Your partner's certificate chain | Optional | Required if your partner certificate was issued by a third-party Certificate Authority (CA) | | Your public encryption certificate | Not used | | | Your private encryption key | Not used | | In this scenario, Stedi will use your partner's public encryption certificate (if provided) and specified encryption algorithm to encrypt the message payload according to the AS2 protocol. Stedi then sends the encrypted payload to your partner's server over HTTPS (which includes a layer of encryption). Your partner will decrypt the HTTPS request and the AS2 payload using private keys. ### Using HTTP or HTTPS with signing Certain trading partners may also require you to sign your messages. Message signing allow partners to verify that your message is authentic and has not been tampered with. This is done by generating a public-private key pair and then sharing your public key with your partner. Your partner will then use your public key to verify that the message was sent by you. Stedi will automatically sign your messages if you upload a signing certificate to your local profile. Additional configuration: | Item | Usage | Comments | | --------------------------------- | -------- | ----------------------------------------------------------------------------------- | | Your public signing certificate | Required | | | Your private signing key | Required | | | Your certificate chain | Optional | Required if your certificate was issued by a third-party Certificate Authority (CA) | | Your partner's public certificate | Not used | | ### With an MDN response requested Some partners may require that you request and accept an [MDN response](/edi-platform/configure/trading-partners/connections/as2/as2-mdn-response). If your partner signs their MDNs, you will need to import your partner's public signing certificate into Stedi to verify the MDN. MDNs can be sent synchronously or asynchronously. For outbound messages, Stedi only supports accepting synchronous MDNs, so you need to tell your partner to send synchronous MDNs if they wish to send an MDN response. Additional configuration: | Item | Usage | Comments | | ----------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | | Your partner's public signing certificate | Optional | Required if your partner signs MDNs | | Your partner's certificate chain | Optional | Required if your partner certificate was issued by a third-party Certificate Authority (CA) | | Your partner's MDN signing algorithm | Required | Can be `None`, `SHA1`, `SHA256`, `SHA384`, or `SHA512` | ## Receive AS2 messages from a partner Receiving AS2 messages from a partner is similar to sending messages to a partner, but the process is reversed. In this case, your partner sends messages to Stedi's AS2 server, and you must provide them with the connection information. Stedi's AS2 servers use HTTP, and therefore require that your partner encrypts their messages according to the AS2 protocol. The following table shows the information needed for setting up an inbound AS2 connection. | Item | Usage | Comments | Exchange with partner | | -------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- | --------------------- | | Your public encryption certificate | Required | Must be 2048-bit or 4096-bit RSA | Yes | | Your private encryption key | Required | Must be 2048-bit or 4096-bit RSA | No | | Your certificate chain | Optional | Required if your certificate was issued by a third-party Certificate Authority (CA) | Yes | | Your encryption algorithm | Required | `AES128_CBC`, `AES192_CBC`, `AES256_CBC`, `3DES` | Yes | | [Your AS2 server URL](https://www.stedi.com/app/core/settings) | Required | | Yes | In this scenario, your partner uses your public encryption certificate and specified encryption algorithm to encrypt the message payload. Your partner then sends the encrypted payload to Stedi's server over HTTP, and Stedi uses your private key to decrypt the payload. ### With signing Certain trading partners may also require that you verify the authenticity and integrity of their messages using their signature. Your partner will generate a public-private key pair and then share their public key with you. When you upload this key to Stedi, Stedi uses it to verify that your partner was the party that sent the message. Additional configuration: | Item | Usage | Comments | | ----------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | | Your partner's public signing certificate | Required | | | Your partner's certificate chain | Optional | Required if your partner certificate was issued by a third-party Certificate Authority (CA) | ### With an MDN response returned Your partner may request that you send an [MDN response](/edi-platform/configure/trading-partners/connections/as2/as2-mdn-response) acknowledging that you have received their message. Stedi automatically sends MDNs when requested in an inbound message and delivers them either asynchronously or synchronously, depending on the specified parameters in your partner's request. Your trading partner's requests may specify that MDN responses should be signed. If a signed MDN is requested and you have imported your public and private signing keys, Stedi signs the MDN using the algorithm specified in the request. If you have not imported your signing keys, Stedi returns an unsigned MDN, as per RFC 4130 section 7.3.1. Additional configuration: | Item | Usage | Comments | | ------------------------------- | -------- | ----------------------------------------------------------------------------------- | | Your public signing certificate | Optional | | | Your private signing key | Optional | | | Your certificate chain | Optional | Required if your certificate was issued by a third-party Certificate Authority (CA) | ## Summary of required configuration The following tables summarize the required configuration based on different scenarios. **For all AS2 connections:** | Item | Usage | Source | | --------------------- | --------------- | -------------------------------------------- | | Your partner's AS2 ID | Always required | Provided by partner | | Your AS2 ID | Always required | [Self-assigned](#choose-your-as2-identifier) | **For sending AS2 messages:** | Item | Usage | Source | | -------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | Your partner's AS2 server URL | Required | Provided by partner | | Your partner's public encryption certificate | Required if using HTTP, optional if using HTTPS | Provided by partner | | Your partner's encryption algorithm | Required if using HTTP, conditionally required if using HTTPS + AS2 encryption | Provided by partner | | Your partner's certificate chain | Conditionally required if your partner certificate was issued by a third-party CA | Provided by partner | | Your partner's public signing certificate | Required if MDNs will be returned | Provided by partner | | Your partner's certificate chain | Conditionally required if your partner certificate was issued by a third-party CA | Provided by partner | | Your public signing certificate | Optional if your partner requires signed messages | [Self-generated](#create-your-signing-and-encryption-certificates) or CA | | Your private signing key | Optional if your partner requires signed messages | [Self-generated](#create-your-signing-and-encryption-certificates) | | Your certificate chain | Conditionally required if your certificate was issued by a third-party CA | CA | **For receiving AS2 messages:** | Item | Usage | Source | | ---------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | Your AS2 server URL | Required | [Core Settings page](https://www.stedi.com/app/core/settings) | | Your public encryption certificate | Required | [Self-generated](#create-your-signing-and-encryption-certificates) or CA | | Your private encryption key | Required | [Self-generated](#create-your-signing-and-encryption-certificates) | | Your certificate chain | Conditionally required if your certificate was issued by a third-party Certificate Authority (CA) | CA | | Your encryption algorithm | Required | [Self-generated](#create-your-signing-and-encryption-certificates) | | Your public signing certificate | Optional if your partner requires signed MDNs | [Self-generated](#create-your-signing-and-encryption-certificates) or CA | | Your private signing key | Optional if your partner requires signed MDNs | [Self-generated](#create-your-signing-and-encryption-certificates) | # Configure AS2 connections Once you have gathered the [required setup information](/edi-platform/configure/trading-partners/connections/as2/as2-requirements), you can configure your Stedi AS2 connection. ## Choose your AS2 identifier The AS2 protocol requires that the sender and receiver provide each other with AS2 IDs to help identify and route transactions during the AS2 file exchange process. Your partner will provide their AS2 ID during the onboarding process. There is no central authority that registers or tracks AS2 IDs, so you can choose any value you like. You should choose a value that is unlikely to be used by other companies. It's common to use the same value that you chose for [your ISA ID](/edi-platform/configure/trading-partners/profiles-and-partnerships#create-local-profiles) when you created your Local profile. An AS2 ID must be between 1-128 printable ASCII characters (except double quote or backslash), and is case sensitive. It's customary to use all capitalized letters and include no spaces. ## Create an AS2 connection Creating an AS2 connection provisions all the resources required to send and receive data using the AS2 protocol. You can only create one AS2 connection per partnership. To create an AS2 connection: 1. Go to the **Trading partners** page. 2. Click the partnership where you want to add the connection. 3. Click **Create connection**. 4. Select **AS2** as the **Connection type**. 5. Enter a **Connection name**. 6. Enter your **AS2 ID** as the **Local AS2 profile identifier**. 7. (Optional) Under Local profile signing credentials you can upload the three different certificates required: * **Certificate:** Your public signing certificate * **Private Key:** Your private signing key * **Certificate chain:** Only required if you are using certificates and keys generated by a trusted certificate authority (CA) 8. (Optional) By default, your **Local profile encryption credentials** use the same data you supplied for your local signing credentials. If you are using different certificate and key for encryption, toggle **Same as signing credentials** to **OFF** and supply: -**Certificate:** Your public encryption certificate * **Private Key:** Your private encryption key * **Certificate chain:** Only required if you are using certificates and keys generated by a trusted certificate authority (CA) 9. Enter your trading partner's AS2 ID as the **Partner AS2 profile identifier**. 10. (Optional) Under **Partner profile signing credentials**, you can upload the two different certificates: * **Certificate:** Your trading partners’ signing certificate * **Certificate chain:** Only required when your trading partners are using certificates and keys generated by a trusted certificate authority (CA). 11. (Optional) By default, the **Partner profile encryption credentials** use the same data you supplied for your partner signing credentials. If your trading partner is using a different certificate and key for encryption, toggle **Same as signing credentials** to **OFF** and supply: * **Certificate:** Your trading partner's public encryption certificate * **Certificate chain:** Only required when your trading partner is using certificates and keys generated by a trusted certificate authority (CA) 12. (Optional) If you plan to send data to your trading partner, set the **Enable AS2 outbound** to **ON** and enter the **Partner AS2 server URL**, the **MDN response**, and **Encryption algorithm**. * (Optional) If your trading partner requires **Basic authentication**, click **Advanced** > **Enable basic access authentication**, and enter the **Username** and **Password**. 13. (Optional) If you plan to receive data from your trading partner, set the **Enable AS2 inbound** to **ON** and enter the **Encryption algorithm**. Note that if this is the first time you are enabling inbound AS2, you must click **Enable inbound AS2** and wait for the server to be provisioned before you can finish creating the connection. This process provisions a unique server URL for you to share with your partners. 14. Click **Create connection**. You must have enabled one or both of the Inbound or Outbound sections, before you can create the connection. ## Certificates and keys Before you configure your AS2 connection, you need to prepare the certificates that you will use. This involves generating your own certificates as well as requesting certificates from your trading partner. A certificate consists of both a public key and a private key. In AS2, there are two types of certificates: * **Signing certificate:** This certificate allows you and your partners to verify the message sender's identity. * **Encryption certificate:** This certificate allows you and your trading partners to encrypt and decrypt messages. Some partners require two certificates – one for signing and one for encryption. Others may want you to use the same certificate for both tasks. For example, Walmart's AS2 portal only asks you to upload a single certificate. Follow the instructions from your trading partner when defining your AS2 configuration. If either you or your partner are using a certificate issued by a third-party Certificate Authority (CA), you can skip the certificate creation steps and use the provided certificate and key directly. If you are sending files to a trading partner's HTTPS endpoint, you must use an SSL certificate signed by a publicly-trusted certificate authority (CA). Self-signed certificates for HTTPS are not currently supported. Certificates with the following cryptographic algorithms and key sizes are supported: * 2048-bit RSA * 4096-bit RSA ### Convert certificates and keys between formats The format in which the encryption materials are provided to you by your trading partner may be different than the PEM format that Stedi AS2 requires. You can use OpenSSL utilities to convert certificates and keys between different formats. Convert `CRT` to `PEM`: `openssl x509 -in cert.crt -out cert.pem` Convert `CER` to `PEM`: `openssl x509 -in cert.cer -out cert.pem` Convert `DER` to `PEM`: `openssl x509 -in cert.der -out cert.pem` ### Create your signing and encryption certificates If your trading partner requires unique certificates for signing and encryption, run the command twice. For each run, change the key names to indicate whether they are for signing or encryption. For example, use `acme-signing-private.pem` for the first run and `acme-encryption-private.pem` for the second run. Create a new certificate. The `-days` option specifies the number of days the certificate will remain valid. ```bash openssl req -x509 -newkey rsa:4096 -keyout .pem \ -out .pem -sha256 -days 365 -nodes ``` Enter information to identify your organization. You don’t need to fill out all the fields, but you should specify what you can. ## Static IP addresses All AS2 connections in your Stedi account use the same set of static IP addresses for outbound EDI. If you need to allowlist these addresses, please [contact customer success](https://www.stedi.com/contact) for a full list. # Bucket Connections Please [contact us](https://www.stedi.com/contact) if you need access to this feature. For advanced use cases that other connection types can't cover, Stedi offers bucket connections. We recommend using other connection types when possible. If you think your use case requires a bucket connection, reach out to [support](https://www.stedi.com/contact) for help setting it up. To create a bucket connection: 1. Select **Bucket** as the **Connection Type**. 2. Enter a descriptive **Connection name**. 3. Select a **root path**. This is the directory in which the inbound and outbound transaction directories will be created. Stedi will automatically suggest a root path based on the partnership ID. You can change this if needed. 4. Choose an inbound directory name that identifies where inbound files should be retrieved for processing. 5. Choose an outbound directory name that identifies where outbound files should be placed when created. 6. Click the **Create connection** to save the connection. You can now associate this connection with one or more [transaction settings](/edi-platform/configure/trading-partners/transaction-settings). # Choosing a connection type Often, your trading partner will request that you set up a specific type of connection protocol. However, it's important to understand the pros and cons of each approach. ## Connection recommendations We recommend the following in order of most preferred to least preferred: 1. **[Stedi-run SFTP/FTPS](/edi-platform/configure/trading-partners/connections/stedi-ftp):** This connection type is extremely simple to set up and requires no ongoing maintenance. Outbound files sent to partners using Stedi SFTP are instantly available for partners to pick up. Inbound file processing is event-driven, and Stedi processes files instantly upon receipt. Stedi SFTP scales virtually infinitely. However, most large trading partners are unwilling to connect to external SFTP servers and require that you connect to their server instead. 2. **[Remote SFTP/FTPS](/edi-platform/configure/trading-partners/connections/remote-ftp):** Stedi can also connect to partner or third-party SFTP/FTPS/FTP servers. Stedi delivers outbound files to your trading partners instantly and processes inbound files on a polling schedule. By default, Stedi polls every 5 minutes, but you can set a custom polling interval in the connection's configuration settings. 3. **[AS2](/edi-platform/configure/trading-partners/connections/as2/as2-overview):** For partners that are unable to connect over SFTP, Stedi offers a hosted AS2 option. The AS2 protocol comes with serious drawbacks, so we recommend only using it as a last resort. **If your partner requests AS2 connectivity, we strongly recommend asking if SFTP is an option instead.** ## Problems with AS2 AS2 has several significant drawbacks: * It is tedious to set up and requires getting complex, unfamiliar configuration settings just right. Debugging AS2 connection issues often involves getting both parties on a call to dive into detailed logs to figure out what is preventing the complex series of handshakes from completing successfully. * It requires generating, distributing, and regularly updating certificates on an ongoing basis. This process can be labor-intensive and requires meticulous management and coordination with trading partners. Any lapse in the process leads to transaction processing downtime. * Once set up, AS2 servers are typically inefficient at processing large files and high transaction volume. ### Why trading partners still want AS2 Regardless of its drawbacks, trading partners – particularly in the retail space – often push for AS2 as a preferred connection type. There are several reasons for this preference. * **Historical:** When AS2 was first developed, it was positioned as way to move from closed, proprietary VANs (Value-Added Networks) to internet-based EDI. AS2 provided a way for retailers and suppliers to circumvent VANs and connect directly. Many retailers today still associate AS2 with "direct connectivity," despite the fact that SFTP provides a functionally identical but more modern mechanism. * **Real-time communication:** There's a perception amongst retailers that AS2 connections are faster than SFTP. When an AS2 message is sent from one a retailer to its supplier, the supplier's AS2 server receives the message in real-time. In contrast, when a retailer places a file on its SFTP server, it's up to the supplier to pick up the file at their own discretion. Many legacy EDI platforms are unable to poll faster than 30 minute intervals, which slows down the flow of transactions. By default, Stedi polls for files at 5-minute intervals, and can poll as often as once per minute (though we don't recommend a one-minute interval because retailer SFTP servers are often quite slow and the poller can't finish processing the first polling request by the time the second request is initiated). ### Why we recommend SFTP instead Modern data transmission technologies have now made many AS2 features obsolete. For the following reasons, we strongly recommend using SFTP instead of AS2 when possible. * **Security:** SFTP, built on SSH (Secure Shell), provides robust encryption and secure data transfer capabilities. This makes the encryption aspect of AS2 less unique, as SFTP offers similar security features. * **Authentication:** SFTP supports strong authentication mechanisms and ensures data integrity during transfer. This diminishes the advantages of AS2 digital signature and MDN features. * **Ease of use and maintenance:** SFTP is generally considered easier to implement and maintain - there are no certificates to update or MDNs to manage. * **Network compatibility:** SFTP is widely compatible with various network configurations and firewalls, making it more adaptable across different IT environments than AS2. * **Performance and scalability:** SFTP tends to be more performant and scalable, especially for larger files or higher volumes of data transfer. # Connections overview You can use Connections to exchange EDI files with trading partners via SFTP, FTPS, FTP, or AS2. ## Prerequisites Before adding a connection, you need to set up a [partnership](/edi-platform/configure/trading-partners/profiles-and-partnerships). ## Create a connection To create a connection: 1. Go to the [**Trading partners**](https://www.stedi.com/app/core/partnerships) page. 2. Click the partnership where you want to add the connection. 3. Click **Create connection**. 4. Select the desired **Connection type**. ### Connection types The available connection types are [Stedi SFTP/FTPS](/edi-platform/configure/trading-partners/connections/stedi-ftp), [Remote SFTP/FTPS](/edi-platform/configure/trading-partners/connections/remote-ftp), and [AS2](/edi-platform/configure/trading-partners/connections/as2). The connection type you choose depends on your and your trading partner's requirements. Visit [Choosing a connection type](/edi-platform/configure/trading-partners/connections/choosing-the-right-connection-type) for our recommendations and details about the pros and cons of each type. ### Inbound file encoding By default, Stedi generates EDI files with UTF-8 encoding and assumes UTF-8 encoding for inbound files. However, some trading partners may send files containing extended Latin characters, such as `ä`, `é` or `ñ`. Files with Latin characters may be encoded in an **extended** ASCII encoding, such as Windows-1252. In these cases, you should specify the appropriate file encoding to ensure Stedi interprets the data correctly. To set the file encoding for inbound EDI files, click a connection to go to its details page. In **Inbound settings** choose a **File encoding** format. Stedi supports UTF-8 and Windows-1252. {' '} UTF-8 is backward compatible with ASCII-encoded files and suitable for most cases. We recommend leaving this setting as the default unless your trading partner tells you otherwise.{' '} ## Next steps After you create a connection, we recommend creating [transaction settings](/edi-platform/configure/trading-partners/transaction-settings) that define the EDI transactions you plan to exchange with your trading partner. # Remote SFTP/FTPS Connections Stedi connects to an external SFTP, FTP, FTPS server to exchange files with your trading partner. This could either be a server that your trading partner hosts, or a server that you host outside of Stedi on existing infrastructure. This is the most common connection type to use, since most large trading partners will require you to connect to their server instead of using yours. Your trading partner will provide you with the connection information required to set up the connection. This typically includes the server address, port, username, and password or private key. ## Create Remote SFTP/FTPS connections To create a Remote SFTP/FTPS connection: 1. Select **Remote SFTP/FTPS** as the **Connection Type**. 2. Enter the **Host** (the remote server address) and specify the **Port**. 3. Enter authentication credentials. Enter a **Username**, and either a **Password** or a **private key** from your local machine. 4. Specify the **Root directory** to use in the remote server. 5. Stedi will automatically suggest an internal **Connection name**. This is never visible to your trading partner and is used for unique identification with your Stedi account only. If the name that's suggested isn't sensible to you, you can change it to anything you wish. You cannot edit the name after it has been created. 6. (Optional) Use the **Advanced** menu if you need to specify the number of **Retries**, the **Connection timeout**, the **Socket timeout**, and **SFTP algorithms** to use. > **Note:** We recommend using the default settings for the majority of use cases. Contact [support](https://www.stedi.com/contact) if you are unsure what settings to use and we'd be happy to help you figure out the right settings. 7. Configure **Inbound settings**. * Set the remote directory where Stedi should retrieve inbound EDI files from your partner. You can use the suggested default if your partner has not provided a specific directory. Stedi only looks for files in this specific directory, it does not search for files within sub-directories. * Use the toggles to set: * How often to poll the remote server * Whether to retrieve only new files created since the last fetch * Whether to delete files after retrieval. 8. (Optional) Set a **Filter pattern** (regex expression) that Stedi will use to retrieve and process files. Stedi only processes files that match the regex criteria. 9. (Optional) Choose a **File encoding** format. We recommend leaving this as UTF-8 unless you know your partner will be sending files with a different encoding type. 10. Set the the remote directory in **Outbound settings** where Stedi should put generated EDI files for your partner to retrieve. You can use the suggested default if your partner has not provided a specific directory. 11. Click **Create connection** to save the connection. You can now associate this connection with one or more [transaction settings](/edi-platform/configure/trading-partners/transaction-settings) and use it to exchange files with your trading partner. ## Shared connections Stedi supports shared remote SFTP/FTPS connections, which allow you to use the same remote server across multiple partnerships. How you configure shared connections depends on your use case. ### Different directory per partner If each trading partner adds files to a distinct directory on the server, configure the remote SFTP/FTPS connections on each partnership to poll the appropriate directory. ### Single directory for all partners If all of your trading partners use the same root directory on the remote server, we recommend the following configuration: 1. Create remote SFTP/FTPS connections in each partnership with automatic polling disabled. 2. Create a separate partnership between your local profile and a new partner profile called `REMOTESFTP` or `REMOTEFTPS`. 3. Add a remote SFTP/FTPS connection to the new partnership and configure it to poll the shared remote server. You do not need to configure any other settings within the partnership. This configuration allows you to easily identify which partnership's connection is polling, making debugging easier. When Stedi polls the remote server, it automatically retrieves and processes all files that match the [filter pattern](#filter-pattern-for-inbound-files) (if set). During processing, Stedi first associates a file with the correct partnership and then processes the file according to that partnership's transaction settings. This process allows Stedi to process all files on the remote server, even if they are not associated with the partnership connection doing the polling. ## Test the connection We recommend testing your connection immediately after creation to ensure you can connect to the remote server. To test the connection: 1. Go to the Partnership and click the **ellipses (...)** next to the SFTP/FTPS connection. 2. Select **Test**. 3. Stedi will attempt to connect to the remote SFTP/FTPS server using the credentials provided in your connection and will show a success or error message accordingly. ## Fetch files manually You can disable automatic polling and retrieve files manually when needed. For example, you may want to retrieve files manually when testing or troubleshooting the connection. To manually fetch files: 1. Go to the Partnership and click the **ellipses (...)** next to the connection. 2. Select **Fetch now**. ## Filter pattern for inbound files You can specify a **Filter pattern** (regex expression) for Stedi to use when retrieving inbound files from the Remote SFTP/FTPS connection. When polling the remote server, Stedi only processes files that match the filter pattern. For example, your trading partner may place files for multiple different entities on the remote server, with different prefixes for each entity. In this case, you could write a regex expression that matches only files with a given prefix. To validate that the expression matches your expectations, you can **Fetch files manually** or wait until the next automatic polling attempt. ### Use cases When you configure a remote FTP connection, you can define a polling interval. If there are files on the remote server under the `inbound` directory that you do **NOT** want to bring over to Stedi when polling, you can define a filter pattern to limit the files that Stedi processes. This is useful when you want to store other file types for different purposes in the folder you have selected to poll. For example, you might store CSV files, images, PDFs, etc. In rare instances, your trading partner might **require** you to configure the inbound subdirectory to be the same as the outbound subdirectory. In this case, it is important that you configure a filter pattern to prevent Stedi from ingesting and processing the outbound files you send to your trading partner. Your filter pattern should identify the naming structure you expect to receive from the trading partner, and you need to make sure that this structure is sufficiently different from the naming structure you use for sending outbound files. ### Example The following expression matches a filename like `INTERCHANGE-GROUP-20231115154001-681896da.edi`, and would prevent Stedi from processing files with names like `INTERCHANGE-681896da.edi` or `681896da.x12`. `^(?\w+)-(?\w+)-(?\d+)-(?\w+).edi$` ## Status and logs Each Remote SFTP/FTPS connection's status and logs can be found on its overview page. To view the overview page, go to the partnership and click the connection's name. An **Available** connection status indicates that Stedi is able to connect to the remote server. The **Logs** detail each connection and polling attempt. ## Static IPs Enabling a static IP address ensures that your Remote SFTP/FTPS connections always use the same source IP address when communicating with a remote server. This may be required if one or more of your trading partners need to add your IP address to an allowlist to enable access. You can enable a static IP address from the [EDI Settings](https://www.stedi.com/app/core/settings) page. # Stedi SFTP/FTPS Connections Stedi creates and hosts a fully-managed server that supports both SFTP and FTPS protocols, along with user credentials you can provide to your trading partner. Your trading partner can use their credentials to connect to the server through either SFTP (using port 22), or FTPS (using port 21). Once you configure the connection, Stedi automatically ingests and processes any files that your trading partner adds to the server and automatically places outbound EDI files on the server for your trading partner to retrieve. This is the easiest way to get started exchanging EDI files with the least amount of configuration. However, your trading partner may require you to use their server instead, especially if they are the larger party. The Stedi SFTP/FTPS connection type supports only username and password authentication. If your trading partner requires key-based authentication, you can use a [Remote SFTP/FTPS connection](/edi-platform/configure/trading-partners/connections/remote-ftp) instead. ## Create SFTP/FTPS connections To create a Stedi SFTP/FTPS connection: 1. Select **SFTP/FTPS** as the **Connection type**. 2. Enter a **Connection name**. 3. If required, provide a specific length for the autogenerated password. 4. Specify an **Inbound directory**. This is the directory that your trading partner will use to send files to you. Any file placed in this directory will be automatically ingested and processed. The default directory is `/inbound` but you can specify a different directory if needed. 5. Specify an **Outbound directory**. This is the directory that your trading partner will use to retrieve files from you. Outbound EDI files will be automatically deposited in this directory. The default directory is `/outbound` but you can specify a different directory if needed. 6. By default, **Delete inbound files on receipt** is selected. Typically, partners want you to delete files after processing. If you want to keep the files, deselect this option. 7. Click **Create connection**. Stedi shows the login credentials for the created user. **Important:** The login credentials will only be displayed once and cannot be retrieved again for security reasons. We recommend immediately saving the login credentials in a secure location such as a password manager. If needed, you can always [regenerate new credentials](#regenerate-credentials). You can now associate this connection with one or more [transaction settings](/edi-platform/configure/trading-partners/transaction-settings) and use it to exchange files with your trading partner. ## Regenerate credentials To generate new login credentials: 1. Navigate to the **Trading partners** page. 2. Click the partnership that contains the connection whose credentials you want to regenerate. 3. Click the **Edit** button. 4. Under the **Username** field, click **Regenerate credentials**. ## Static IPs Some partners will need to know Stedi SFTP/FTPS's IP addresses in order to allow internal systems to establish a connection. Stedi SFTP/FTPS uses the following IPs: `18.119.51.218` and `18.206.132.233` These IPs apply only to Stedi-hosted SFTP/FTPS. You can enable different static IPs for Remote SFTP/FTPS in [EDI Settings](/edi-platform/configure/global-settings). ## Status and details You can find details about each Stedi SFTP/FTPS connection on its overview page. To view the overview page, navigate to the partnership and click the connection's name. # Acknowledgments Your trading partner may send you TA1s in response to outbound EDI files. You may also need to send your trading partner a TA1 and/or a functional acknowledgment (997 or 999) in response to each inbound EDI file. These acknowledgments confirm that you received the transaction and help your trading partner know everything is working as expected. Stedi can automatically generate acknowledgments for each inbound transaction and deliver them to your trading partner. ## TA1s [TA1 Interchange Acknowledgments](https://www.stedi.com/edi/x12-008040/segment/TA1) indicate receipt of an interchange and identify any errors in the interchange's envelope (`ISA` and `IEA`) information. ### Inbound You don't need to create a transaction setting to receive TA1s from your trading partners. Stedi automatically processes inbound TA1s and displays the data in the [Files](https://www.stedi.com/app/core/file-executions) and [Transactions](https://www.stedi.com/app/core/transactions) pages for inspection. ### Outbound Stedi can automatically send both positive and negative TA1s in response to inbound transactions from your trading partner. If you specify a connection for automatic acknowledgments, Stedi sends the TA1 to that connection. Otherwise, Stedi sends the TA1 through the connection that received the inbound file. You can review the TA1s Stedi sends to trading partners on the [Files](https://www.stedi.com/app/core/file-executions) page in the Stedi app. #### Positive TA1s Positive TA1s contain code `A` in `TA104`, indicating that the interchange was accepted without errors. Stedi will then process the transaction and create a record in the Stedi app. Note that a positive TA1 only indicates that Stedi received the interchange and that the interchange envelope does not contain any of the errors that trigger a [negative TA1](#negative-ta1s). The transaction data can still fail Stedi’s validation and processing. For example, your partner could receive a positive TA1 and then a 999 rejection (if configured) for the transaction itself due to non-compliant EDI. #### Negative TA1s Stedi only generates negative TA1s for specific errors. If the interchange envelope contains a different error than the ones listed, Stedi still sends a positive TA1 (if configured) so your trading partner can confirm you received the transaction. Your trading partner may receive the following types of negative TA1s: * **Accepted with errors:** TA1s with [code `E` in `TA104`](https://www.stedi.com/edi/x12/segment/TA1#TA1-04) indicate that the interchange was accepted with errors. In these cases, Stedi still proceeds with processing the transaction and creates a record in the Stedi app. Stedi generates TA1s with code `E` for the following `TA105` error types: * `014`: Invalid Interchange Date Value * `015`: Invalid Interchange Time Value * **Rejected because of errors:** TA1s with [code `R` in `TA104`](https://www.stedi.com/edi/x12/segment/TA1#TA1-04) indicate that the interchange was rejected due to one or more errors. Stedi doesn't process the interchange and doesn't create a record in the Stedi app. Stedi generates TA1s with code `R` for the following `TA105` error types: * `001`: The Interchange Control Number in the Header and Trailer Do Not Match. The Value From the Header is Used in the Acknowledgment * `021`: Invalid Number of Included Groups Value | For example, the interchange envelope indicates that there are five functional groups, but only four are present in the interchange. * `027`: Invalid Component Element Separator | The data cannot use letters, numbers, whitespace, or the underscore character as a separator between EDI elements. #### Enable automatic TA1s To enable autogenerating outbound TA1s for trading partners: 1. Go to the partnership. 2. Click the pencil next to **Acknowledgments**. 3. Select an option under **Interchange Acknowledgments (TA1)**: * **Never:** This is the default setting. * **When requested**: Stedi sends a TA1 according to the [code provided in `ISA14`](https://www.stedi.com/edi/x12/segment/ISA#ISA-14). There are four possible codes: * `0`: Never send a TA1 * `1`: Always send a TA1 (positive or negative) * `2`: Only send TA1s with code `R` (rejected) * `3`: Only send TA1s with code `R` or code `E` (accepted with errors) * **Always:** Stedi sends a TA1 for every successful inbound transaction received over a connection within this partnership. 4. Select an existing **Connection** within the partnership where Stedi will deliver generated TA1s. * (SFTP/FTPS only) Specify an optional **Subdirectory**. Stedi will deliver generated acknowledgments to this subdirectory. We don't recommend specifying a subdirectory unless your trading partner has instructed you to do so. 5. (Optional) Enter a JSONata expression to set a custom filename for generated acknowledgments. Available JSONata expressions are `& (Concatenation)` and `$millis`. If you do not set a filename, Stedi uses the **File Execution ID**. 6. Click **Save**. ## 997s and 999s [997 Functional Acknowledgments](https://www.stedi.com/edi/x12/transaction-set/997) and [999 Implementation Acknowledgments](https://www.stedi.com/edi/x12/transaction-set/999) are functional acknowledgments that confirm receipt of a transaction and indicate whether it was accepted or rejected. The acknowledgment also provides information about errors in the transaction, if present. While they serve the same basic purpose, 999s are more detailed than 997s and are currently only used in healthcare. ### Inbound You must create [inbound transaction settings](/edi-platform/configure/trading-partners/transaction-settings) if your trading partner plans to send you 997 or 999 functional acknowledgments. ### Outbound When sending outbound functional acknowledgments, you should never return both a 997 and a 999 for a given file. 999s are commonly returned for the following healthcare transaction sets: * [270 Health Care Eligibility, Coverage or Benefit Inquiry](https://www.stedi.com/app/guides/view/hipaa/health-care-eligibility-benefit-inquiry-x279a1/01GRYB6GTDJ4MEP5Z16CGMQWT6) * [271 Health Care Eligibility Benefit Response](https://www.stedi.com/app/guides/view/hipaa/health-care-eligibility-benefit-response-x279a1/01GS66YHZPB37ABF34DBPSR213) * [276 Health Care Claim Status Request](https://www.stedi.com/app/guides/view/hipaa/claim-status-request-x212/01GRYB6A4XEJQ61Y2K2KT606E5), * [277 Health Care Information Status Notification](https://www.stedi.com/edi/x12/transaction-set/277) * [278 Health Care Services Review Information - Response](https://www.stedi.com/app/guides/view/hipaa/health-care-services-review-information-response-x217/01GRYB6C27KFB6H1M8MVYMQDKK) * [820 Payroll Deducted and Other Group Premium Payment for Insurance Products Examples](https://www.stedi.com/app/guides/view/hipaa/payroll-deducted-and-other-group-premium-payment-for-insurance-products-examples-x218/01GRYB6CPB1S1257NJJP6K497B) * [834 Benefit Enrollment and Maintenance](https://www.stedi.com/app/guides/view/hipaa/benefit-enrollment-and-maintenance-x220a1/01GRYB6D6RAWSG8ATBD6GXM13C) * [835 Health Care Claim Payment/Advice](https://www.stedi.com/app/guides/view/hipaa/health-care-claim-paymentadvice-x221a1/01GRYB6DS30MGXWBPFZCM3695E) * [837 Health Care Claim](https://www.stedi.com/edi/x12/transaction-set/837) When configured, Stedi autogenerates a 997 or 999 acknowledgment for every successful inbound EDI transaction received over a partnership connection, even if the transaction set has not been explicitly configured as an inbound transaction setting. Acknowledgments are generated at the functional group level and contain complete `ISA` and `GS` envelopes, including control numbers. If a file fails during validation or processing, Stedi does not send an acknowledgment until the file is processed successfully. Per the X12 EDI specification, Stedi doesn't generate acknowledgments in response to inbound acknowledgments. A [`file.failed.v2` event](/edi-platform/operate/event-types#file-failed) is emitted when Stedi fails to process a file. You can use this event to trigger a 997 rejection. ### Enable automatic 997s or 999s Before you begin, you must define at least one [connection](/edi-platform/configure/trading-partners/connections/index) for this partnership. To enable automatic 997 or 999 generation: 1. Go to the partnership. 2. Click the pencil next to **Acknowledgments**. 3. Select **997s** or **999s**. 4. Select an existing **Connection** within the partnership. Stedi delivers generated acknowledgments using this connection. * (SFTP/FTPS only) Specify an optional **Subdirectory**. Stedi will deliver generated acknowledgments to this subdirectory. We don't recommend specifying a subdirectory unless your trading partner has instructed you to do so. 5. (Optional) Enter a JSONata expression to set a custom filename for generated acknowledgments. Available JSONata expressions are `& (Concatenation)` and `$millis`. If you do not set a filename, Stedi uses the **File Execution ID**. 6. Click **Save**. # Partnerships The first step to add a trading partner is creating a partnership. ## What is a partnership? Partnerships describe all aspects of the EDI relationship between two profiles in your Stedi account, such as which transaction sets they will exchange and other important information for processing EDI files. ### Types of profiles Profiles contain the basic information required to construct a valid EDI file. Generally, each profile represents a unique business entity. For example, if you are a brand, you would have a profile for your brand and a profile for each of your retailers. You can create two types of profiles on Stedi: **Local** profiles for your company (or a company you represent) and **Partner** profiles for the companies you do business with. Typically, you create a single local profile for your company and a single partner profile for each of your trading partners. If you're using Stedi to represent multiple companies, then you should create multiple local profiles – one for each of the companies you represent. For example, you may have multiple brands that you own, or you may be a SaaS provider using Stedi to power your product's EDI functionality. In addition to containing important information for processing EDI, profiles also determine the direction of EDI files: * EDI files are labeled as **inbound** when the **Local** profile is the **receiver**. * EDI files are labeled as **outbound** when the **Local** profile is the **sender**. ## Create partnerships To create a partnership manually: 1. Go to the [**Trading partners**](https://www.stedi.com/app/core/partnerships) page. 2. Click **Create partnership**. 3. Enter the information for a [local profile](#create-local-profiles) and a [partner profile](#create-partner-profiles), or select existing profiles from the menus. ### Create local profile For most use cases, you will only need to set up a single local profile for your company. You can create a new local profile as part of the [create a partnership](#create-partnerships) flow, or from the [Trading partners](https://www.stedi.com/app/core/partnerships) page. You must enter the following information for each local profile: * **ID Qualifier** and **Interchange ID**: These values are used to populate the [ISA header](https://www.stedi.com/edi/x12/segment/ISA) of an EDI file. Your Interchange Qualifier and ID are used by your partner to route EDI files in a similar way to email addresses in an email system. Your trading partner will ask you to provide these values so that they can set you up in their EDI system. * In most industries, you can choose these values yourself, since there is no central authority that registers and validates Interchange IDs. A safe choice for the ID Qualifier is `ZZ`, which is a catch-all code that means "Mutually Defined". For the Interchange ID, you can use your company's name (e.g. `STEDI`) or an identifier that you use internally. It's customary for these values to be all uppercase with no spaces or special characters. * If you are unsure of what to use, or if your trading partner has specific requirements, [reach out to us](https://www.stedi.com/contact) and we can help you choose the right values. * **Identifier**: This is never visible to your trading partner and is used for unique identification within your Stedi account only. You can change this value to anything you wish. You cannot edit the name after the profile has been created. * **Application ID**: This is used to populate the [GS header](https://www.stedi.com/edi/x12/segment/GS) of an EDI file. Stedi will automatically suggest the same value that you inputted for your Interchange ID, which is the right choice for most use cases. This can be changed at any time, and you can add multiple application IDs if needed, so don't worry about getting it right up front. If the need for multiple application IDs arises in the future, you can add them as-needed. For advanced use cases, you can also override the Application ID on the partnership itself. ### Create partner profile You need to create a partner profile for each of your trading partners. You can create a new partner profile as part of the [create a partnership](#create-partnerships) flow, or from the [Trading partners](https://www.stedi.com/app/core/partnerships) page. You must enter the following information for each partner profile: * **ID Qualifier** and **Interchange ID**: Your partner will provide you with this information as part of the onboarding process. If they haven't already, you should request this from them. If you get stuck or aren't sure what to ask, [reach out to us](https://www.stedi.com/contact) and we can help ensure the profile is set up correctly. * **Identifier**: This is never visible to your trading partner and is used for unique identification within your Stedi account only. You cannot edit the name after the profile has been created. * **Application ID**: This value is used to populate the [GS header](https://www.stedi.com/edi/x12/segment/GS) of an EDI file. Stedi will automatically suggest the same value that you inputted for your partner's Interchange ID, which is the right choice for most use cases. Some trading partners use the GS ID to specify a specific department within their business. If your trading partner has asked you to use a specific GS ID (or multiple IDs), you can add them here. This can be changed at any time. ### Finish partnership Once you have created the local and partner profiles, finalize the partnership: 1. Review the autogenerated **Partnership identifier**. The Partnership identifier is never visible to your trading partner and is only used for unique identification with your Stedi account. You can change it to any value that is the most helpful to you. You cannot edit the name after the profile has been created. 2. Click **Create Partnership**. You will be brought to the partnership details page where you can define additional settings. ## (Advanced) Auto-configure from sample EDI files If you have EDI files from your trading partner, you can use the auto-configure option to create profiles and partnerships based on those sample files. This is an advanced option that is best suited for migrations. Stedi extracts information from the file to generate two profiles - one for you and one for your partner – as well as a new partnership between them. To automatically generate profiles and partnerships from EDI files: 1. Go to the [**Trading partners**](https://www.stedi.com/app/core/partnerships) page and click **Create partnership**. 2. Click **Advanced** and then the link to **auto-configure partnerships**. 3. Upload an EDI file. 4. Review the profiles to ensure the pre-populated fields are correct. Refer to [create local profiles](#create-local-profiles) and a [create partner profiles](#create-partner-profiles) for field descriptions. > **Important:** Set your company as the **Local** profile and your trading partner as a **Partner** profile. 5. By default, a partnership will also be created when you click **Create**. To disable the creation of a partnership, toggle the **Create partnership** option to OFF. 6. Click **Create**. Two profiles and the new partnership are created. You can view the new profiles and partnership on the [**Trading partners**](https://www.stedi.com/app/core/partnerships) page. ## Next steps After you create profiles and partnerships, you can configure the details of each partnership to start processing EDI files. ### Configure connections Within each partnership, you can create one or more SFTP, FTP, FTPS, or AS2 connections in order to exchange files with your trading partner. Visit [connections](/edi-platform/configure/trading-partners/connections) for details. ### Configure transaction settings Within each partnership, you can define the EDI transaction sets you plan to exchange with trading partners. Visit [transaction settings](/edi-platform/configure/trading-partners/transaction-settings) for details. ### Configure acknowledgments Stedi can automatically generate a 997 Functional Acknowledgement or a 999 Implementation Acknowledgment for each inbound transaction within a partnership. Visit [Functional acknowledgments](/edi-platform/configure/trading-partners/functional-acknowledgments) for details. # Transaction settings Within each [partnership](/edi-platform/configure/trading-partners/profiles-and-partnerships), you can specify the EDI transaction sets that you plan to exchange with that trading partner. For example, you may want to receive inbound 850 Purchase Orders from a retailer and send outbound 810 Invoices to them. This would involve creating an inbound transaction setting for 850 Purchase Orders and an outbound transaction setting for 810 Invoices. ## Create transaction settings To create a transaction setting, navigate to the partnership and click either: * **Create inbound transaction setting** to configure a transaction set you plan to receive from your trading partners * **Create outbound transaction setting** to configure a transaction set you plan to send to your trading partner. ### Choose a transaction set When you configure a transaction setting, you must select a machine-readable EDI specification ([Stedi guide](/edi-platform/guides/index)) for the transaction set. Guides allow Stedi to validate and parse (inbound) or validate and generate (outbound) EDI data according to your and your trading partner's specific requirements. * **Import from network (recommended):** Search for your trading partner and click **Select** to import a local copy of the guide into your account. * **My account:** Select an existing guide from your account. * **Base guide:** Stedi validates the transaction against the generic X12 specification. This option is useful for testing inbound flows when your partner hasn't yet provided a guide. We do not recommend using it for outbound flows except in rare, advanced use cases. * Select the X12 **Release**. The release is present in the `GS` segment of every EDI file, and also should be specified in your partner’s documentation. * Select the **Transaction set**. The transaction set is the EDI transaction you are receiving from your partner. ### (Inbound) Configure fragments If the guide you choose is set up to use [fragments](/edi-platform/fragments), you can enable fragments for the transaction setting. Fragments allow you to split large transactions from Stedi into smaller chunks for downstream ingestion. ### (Outbound) Application IDs Stedi automatically suggests the default **Application IDs** that were assigned to the local and partner profiles. You can override these values if needed. For example, some trading partners may assign a specific `GS` ID to you during the onboarding process. Since this `GS` ID is used only for this partnership, you would not want to put it in your local profile. ### (Outbound) Connection Specify the **Connection** to deliver generated EDI files. If no connection is specified, you can't generate outbound EDI files for this transaction. For **SFTP/FTPS**, You can optionally add a subdirectory that Stedi uses for this transaction set only. For example, your trading partner may require that you place all 810 Invoices in an `/810` subdirectory. We don't recommend specifying a subdirectory unless your trading partner has instructed you to do so. ### (Outbound) Custom filename expression By default, Stedi autogenerates a unique name for outbound files using a UUID. To set a custom filename, open **Advanced settings** and enter a JSONata expression into the **Filename expression** field. You can use `& (Concatenation)`, `$random`, or `$millis` in the expression to generate a unique name based on a random number and/or the processing timestamp. For example, the expression `“EDI850-” & $millis()` results in filenames like `EDI850-5182341242`. ## Control numbers Control numbers are used in the [`ISA` Interchange Control Header](https://www.stedi.com/edi/x12/segment/ISA) and [`GS` Functional Group Header](https://www.stedi.com/edi/x12/segment/GS) of X12 EDI files. You and your trading partners can use them reference EDI files and to detect duplicates and missing data. Control numbers must be unique within a partnership. Stedi handles control numbers automatically for you. When you create a partnership, Stedi sets the control number counters to `0` for both the Interchange (ISA) and Group (GS) levels. Each time you send an outbound EDI file, Stedi increments the control numbers to ensure uniqueness. ### Reset control numbers In rare circumstances, you may need to reset the control numbers for a partnership. For example, if you're migrating from another EDI system, you may need to reset the control numbers to match the last control numbers used in your previous system. To reset control numbers for outbound documents: 1. Go to the partnership where you want to adjust the control numbers. 2. Open the **Advanced settings** menu. 3. Update the **Interchange** or **Group** control numbers as needed. ### Non-numeric control numbers Stedi can translate EDI files containing non-numeric control numbers, if required for your use case. Successful processing requires that you set the `ST-02` and `SE-02` control number elements in the associated Stedi guide to type `String`. ## Timezone and time format Stedi uses the following default values: * **Timezone:** UTC | Used in the `ISA` and `GS` segments * **Time format:** `HHMMSS` | The [GS-05](https://www.stedi.com/edi/x12/segment/GS#GS-05) time element You can change these values in the partnership's **Advanced settings** menu. ## Next steps We recommend configuring [Acknowledgments](/edi-platform/configure/trading-partners/functional-acknowledgments) for inbound transactions within the partnership. We also recommend configuring one or more [webhooks](/edi-platform/configure/webhooks/index) to automatically send events from Stedi to your internal systems and business applications. # Configure webhooks Configuring a webhook involves: * Creating a [credential set](#credential-set) for authentication to the endpoint. * Creating a [webhook](#webhook) that specifies the URL where Stedi should deliver events. * Adding one or more [event bindings](#event-bindings) that trigger the webhook. ## Credential set A credential set defines how to authenticate with a specific API. You can use a single credential set across multiple webhooks. Stedi supports the following types of configurations. | Type | Description | | ---------- | -------------------------------------------------------------------------------------------------------------------------- | | API Keys | The API keys as headers in the request. The most common version is ‘bearer tokens’. | | Basic Auth | [HTTP Basic Auth](https://developer.mozilla.org/en-US/Web/HTTP/Authentication), where you provide a username and password. | | None | For endpoints that don't require any authentication. | ### Unauthenticated endpoints When using the 'None' credential set type in webhooks, it's functionally the same as using 'API Keys'. However, we set a dummy value for `Header name` and `Value` (`x-stedi-noauth` and `dummy`). Since the receiving API isn't authenticating the call, it will ignore these values and accept the request. ### Create credential set You can define a credential set as part of configuring a new webhook. You can also create a new credential set independently and then attach it to one or more webhooks. To create a credential set: 1. Go to the [Webhooks](https://www.stedi.com/app/webhooks) page. 2. Click **Manage credentials**, and then click **Create credential set**. 3. Enter a name. 4. Choose the appropriate **Authentication type**. 5. Enter the details. 6. Click **Create credential set**. ## Webhook A webhook defines which URL endpoint Stedi should call when the webhook is invoked, and which HTTP method to use (`POST`, `PUT`, `GET`, `PATCH`, `DELETE`). You can only attach one credential set to each webhook. However, you might have multiple webhooks for a single system integration, each with a different endpoint. ### Create webhook To create a new webhook: 1. Go to the [Webhooks](https://www.stedi.com/app/webhooks) page. 2. Click **Create webhook**. 3. Enter a name. 4. Choose a **Method** and enter an **Endpoint** URL. This is where Stedi delivers the events when the webhook is invoked. 5. Select a **Credential set** to use for authentication or create a new one for this endpoint. 6. (Optional) Set the **Concurrency**. You can set the maximum number of deliveries that Stedi will attempt to deliver to the endpoint at one time. This can help you avoid overloading the target service. ## Event bindings Event bindings allow you to specify which events trigger the webhook. You can create multiple event bindings for a single webhook. For example, you may want to create an event binding for each type of transaction you want to send to your API. ### Create event binding To create a new event binding: 1. Go to the [Webhooks](https://www.stedi.com/app/webhooks) page. 2. Click the webhook. 3. Click the **Event bindings** tab. 4. Click **New event binding**. 5. Choose an **Event type** and complete the remaining fields. To listen for processed transactions, select **Transaction processed** or **Fragment processed**. Visit [Event types](/edi-platform/operate/event-types) for details about each event. 6. Click **Create binding**. ### Ingest processed transactions You can use the provided download URLs in the following events to retrieve the processed transaction data from Stedi. * [Transaction processed events](/edi-platform/operate/event-types#transaction-processed): An EDI file can contain multiple transactions, so a single EDI file can produce multiple events that each invoke the configured webhook. * [Fragment processed events](/edi-platform/operate/event-types#fragment-processed): When [Fragments](/edi-platform/fragments) are enabled, Stedi emits one fragment processed event for each fragment within the processed transaction. You may want to configure the following settings for transaction processed or fragment processed events: 1. **Transaction set ID:** This is useful if you want to send events for different transaction sets to different endpoints. For example, you could send events for 850 Purchase Orders to one endpoint and events for 860 Purchase Order Change Requests to another. 2. **Partnership ID:** This is useful if you want to send events from different partners to different endpoints. For example, you could send events from processed Walmart transactions to one endpoint and events from processed Target transactions to another. This is less common. 3. **Guide:** This is useful if you want to send events from transactions parsed using different guides to different endpoints. For example, you may receive `005010` 850 Purchase Orders from two different retailers, and those retailers have different guides. Since the transaction payloads will differ, you may want to send them to different API endpoints within your system. 4. (Optional) You can configure the following **Advanced** settings: * **Connection:** This is useful when you are using multiple connections for a single partnership. For example, you may have set up one connection type for test data and a separate connection for production data. * **Mode:** Specify the type of data Stedi is processing. You can choose from **Test** or **Production**. # Webhooks error handling and limitations [Webhooks](/edi-platform/configure/webhooks/configure-webhooks) have certain limitations. If your system's API has different requirements, you can set the target to be: * A function, such as AWS Lambda, Google Cloud Functions, or Azure Functions, which can then call the third-party API * An iPaaS platform, such as Zapier or Workato, which can then call the third-party API. ## HTTP response codes Stedi considers a 2xx response a success, and marks any other response as a failure. Stedi retries events associated with status codes other than `2xx` for up to 4 times with a 90 second wait period inbetween retries. If the maximum number of retries has been exhausted, Stedi adds the event to the [error queue](#error-queue) for the webhook. You can set the **Concurrency** when configuring the webhook to prevent throttling. This setting determines the maximum number of deliveries that Stedi will attempt to deliver to the endpoint at one time. ## Response time The target endpoint must respond within 5 seconds, or the event will be counted as a failed delivery. ## Retries When a delivery fails, Stedi will retry up to 4 times every 90 seconds. After the fifth retry, Stedi moves the event to the error queue. ### Duplicate deliveries If your webook doesn't respond within 5 seconds, Stedi marks that as a failure and then automatically retries. This can result in duplicate deliveries, so we **strongly recommend** implementing ways to manage duplicates delivered through webhooks. ## Error queue Each webhook includes an error queue. Each item in the queue consists of the original event that was attempted to be delivered. This ensures if the target service has some downtime, or anything else goes wrong, the missed events can be retried later. The error queue retains items for 14 days. The order of the error queue is not guaranteed. The downstream service must be designed to be idempotent to handle at-least-once delivery of events, and must accept events out of order. ## Logs To view logs, click the webhook to go to its detail page, and then navigate to the **Logs** tab. ## Deauthorized connections If a webhook sends a message to an endpoint that returns a 401 (Unauthorized) response, the destination will be 'deauthorized'. In this state, the webhook won't be able to deliver messages. If there is an issue with your authentication information (such as the password, API key, or OAuth settings), edit the webhook to fix it. If the authentication information is correct, and there was a different reason for the endpoint returning a 401, you can try again by adding a temporary header. For example, `x-stedi-reauthorize` with today's date as a value. When you save, the webhook will attempt to deliver again. This header can be removed later. Editing the value of a header will also restart deliveries. You will likely have a queue of messages to deliver, so Stedi will automatically start retrying them after you make this change. If the endpoint is still returning an invalid response, the webhook will return to `Deauthorized`. # Webhooks overview Each time you receive an EDI file from a trading partner, you will want to ingest the transactions into your downstream system for processing. You can do this by configuring a webhook. Webhooks allow you to send events from Stedi to third-party services without writing any custom code. Stedi can send webhooks to: * Custom applications using Basic or API Key authorization * Cloud functions, including AWS Lambda, Google Cloud Functions, and Azure Functions * iPaaS platforms, such as Zapier, Workato, or Tray.io * ERPs like NetSuite, SAP, or Oracle. The most common use case is ingesting processed transaction data into your internal systems and business applications. You can configure a webhook to send `transaction.processed.v2` events to your system and then programatically retrieve the processed transaction data from Stedi using the provided download URL. You can also configure webhooks for other [Stedi events](/edi-platform/operate/event-types), like when a processing error occurs. This can be used to trigger alerts in systems like Slack, PagerDuty, or Zendesk for further review. # Glossary ## Composite element A single [element](#element) that contains multiple values of different types, similar to a struct or record. The [specification](#specification) will specify which fields make up a composite element. The values in a composite element are kept apart by a [delimiter](#delimiter). The delimiter to use is specified in the [interchange](#interchange) header. In the following example, values are delimited using a `:`. ``` PRV*LA***ORT:HS:Y~ ``` ## Delimiter A delimiter is used in the [X12 EDI Format](#x12-edi-format) to mark the end of a [segment](#segment) or [element](#element). The end of a [segment](#segment) is [delimited](#delimiter) by a `~` and the end of an [element](#element) by a `*`. Here's an example of two segments, both with three elements. ```edi SE*2*0000~ GE*1*987654321~ ``` There are also delimiters for [repeated elements](#repeated-element) and [composite elements](#composite-element), but these aren't standardized. Instead, these delimiters are specified in the [interchange](#interchange). ## Element An element is a data field within a [segment](#segment). In the [X12 EDI Format](#x12-edi-format), elements in a [segment](#segment) are delimited by a `*`. For example, here's a [segment](#segment) with several elements. ```edi GS*SO*00*00*20210902*1200*987654321*X*008010~ ``` The values an element may contain, are described in a [specification](#specification). ## EDI (Electronic Data Interchange) EDI – Electronic Data Interchange – is an umbrella term for many different “standardized” frameworks for exchanging business-to-business transactions like invoices, insurance applications, train sheets, credit reports. It is often used synonymously with two of the most popular standards – [X12](#x12-edi-format), used primarily in North America, and [EDIFACT](#edifact-format), which is prevalent throughout Europe. Read more: [What makes EDI so hard?](https://www.stedi.com/blog/what-makes-edi-so-hard) ## EDIFACT format A file format for encoding [EDI](#edi) data, standardized by United Nations/Electronic Data Interchange for Administration, Commerce and Transport (UN/EDIFACT). ## Functional group Within an [EDI](#edi) file, a functional group is a set of [transaction sets](#transaction-set). Typically, all the [transaction sets](#transaction-set) within a functional group are intended for the same department within an organization. The beginning of a functional group is marked by the [GS](https://edi.stedi.com/x12-008010/segment/GS) [segment](#segment) and the end is marked by the [GE](https://edi.stedi.com/x12-008010/segment/GE) [segment](#segment). A functional group must be part of an [interchange](#interchange). ## Interchange Within an [EDI](#edi) file, an interchange is a set of [functional groups](#functional-group) which in turn contain [transaction sets](#transaction-set). Typically, the contents of an interchange is intended for a specific organization and the contents of a [functional group](#functional-group) is intended for a specific department within that organization. The beginning of an interchange is marked by the [ISA](https://edi.stedi.com/x12-008010/segment/ISA) [segment](#segment) and the end is marked by the [IEA](https://edi.stedi.com/x12-008010/segment/IEA) [segment](#segment). Every EDI file must have at least one interchange and consequently, every EDI file starts with an [ISA](https://edi.stedi.com/x12-008010/segment/ISA) [segment](#segment) and ends with an [IEA](https://edi.stedi.com/x12-008010/segment/IEA) [segment](#segment). Read more: [Control numbers in X12 EDI](https://www.stedi.com/blog/control-numbers-in-x12-edi). ## Loop A loop is a collection of [segments](#segment) that can appear multiple times in a [transaction set](#transaction-set). The [segments](#segment) in a loop typically have a semantic relationalship, for example, the segments [Party Identification](https://www.stedi.com/edi/x12/segment/N1), [Geographic Location](https://www.stedi.com/edi/x12/segment/N4), and [Communication Contact Information](https://www.stedi.com/edi/x12/segment/COM) together can tell you about a single [trading partner](#trading-partner) and a loop of those segments allows you to refer to multiple [trading partners](#trading-partner) in a [transaction set](#transaction-set). In [X12 EDI Format](#x12-edi-format), there's no special [delimiter](#delimiter) for loops, nor is there a set of [segments](#segment) that mark the begin and end of the loop, like there is for [interchanges](#interchange), [functional groups](#functional-group), and [transaction sets](#transaction-set). Instead, the segments in the loop are just repeated. ```edi N1*21*Stedi*ZZ*ID001~ N4*New York**US~ COM*16*stedi.com~ N1*21*Acme*ZZ*ID002~ N4*Miami**US~ COM*16*acmebread.co~ ``` ## Repeated element A single [element](#element) that contains multiple values of the same type, similar to a homogeneous array. Not every [element](#element) can be repeated; the [specification](#specification) must indicate that it's okay to do so. In [X12 EDI Format](#x12-edi-format), the values in a repeated element are kept apart by a [delimiter](#delimiter). The delimiter to use is specified in the [interchange](#interchange) header. In the following example, values are delimited using a `/`. ```edi AAA*Y***NF/NR/TO~ ``` ## Repeated segment Within an [EDI](#edi) file, some segments can occur multiple times in a row. The [specification](#specification) will tell when a segment can be repeated. In [X12 EDI Format](#x12-edi-format), a repeated segment appears as, well, a segment that's repeated. ```edi NTE**When a segment has need to repeat,~ NTE**How does one accomplish that feat?~ NTE**It's really no bother.~ NTE**One after the other.~ NTE**A solution that's simple and neat.~ ``` ## Segment Within an [EDI](#edi) file, a segment is a set of [elements](#element), where the segment is like a record and the [elements](#element) are its fields. Each segment starts with a segment identifier that tells you which [elements](#element) will follow. The different types of segments and their elements are listed in the [specification](#specification). In the [X12 EDI Format](#x12-edi-format), segments are [delimited](#delimiter) by a `~`. It's also common to add a new line character after the [delimiter](#delimiter), but that's for human readability only and has no semantic value. ## Specification A specification describes the data schema of a [transaction set](#transaction-set). It lists the [loops](#loop) and [segments](#segment), the order in which they appear, and the [elements](#element) within the [segments](#segment). The specification gives you all the information you need to write or interpret an [EDI](#edi) document that conforms to that specification. [X12](#x12) has published [many specifications](https://edi.stedi.com/). A [trading partner](#trading-partner) can use these specifications directly, or they can base their own specification on one of them. Find popular EDI specifications in [the Stedi Network](https://www.stedi.com/edi/network). ## Trading partner Any business that sends or receives business transactions. ## Transaction set A transaction set is a type of business document, for example a purchase order, or a booking cancellation. Each transaction set is based on a [specification](#specification) that describes what data the transaction set can and must contain. There is a [list of standardized transaction sets](https://edi.stedi.com/). The standard transaction sets are designed to be widely applicable. A [trading partner](#trading-partner) can take a transaction set, base its own [specification](#specification) on it, and only accept the data it knows how to handle. Many of these [business-specific transaction sets are available on Stedi](https://www.stedi.com/edi/network). ## X12 An organization that develops and maintains the [X12 EDI](#x12-edi-format) standards. ## X12 EDI Format A file format for encoding [EDI](#edi) data, standardized by [X12](#x12). It's text-based and makes use of [delimiters](#delimiter) to mark the [segments](#segment) and [elements](#element). # What is EDI? Electronic Data Interchange (EDI) is a structured way for businesses to send and receive documents electronically. It was created in the 70's as a replacement for paper documents. EDI is like a schema to cover all possible business transactions across most industries, but it existed before the Internet was invented. Today, most every large company uses it including Amazon, Walmart, and FedEx. Prior to EDI, businesses used to exchange paper transactions and record those transactions into a hand-written book called a ledger, but modern businesses use one or many software applications, called business systems, to facilitate operations. There are many types of business systems, ranging from generic software suites like Oracle, SAP, and NetSuite to vertical-specific products that serve some particular industry, like purpose-built systems for healthcare, agriculture, or education. When broken down to its simplest definition, EDI can be thought of as "getting data from one business system into another". ## Common Uses of EDI There are more than 300 different EDI transaction types. The following table contains examples of common EDI transactions. | | | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Logistics** |
  • [204](https://www.stedi.com/edi/x12/transaction-set/204) Request pickup of a shipment (load tender)
  • [990](https://www.stedi.com/edi/x12/transaction-set/990) Accept or reject the shipment (response to a load tender)
  • [214](https://www.stedi.com/edi/x12/transaction-set/214) Shipment status update
  • [210](https://www.stedi.com/edi/x12/transaction-set/210) Invoicing details for a shipment
| | **Warehousing** |
  • [940](https://www.stedi.com/edi/x12/transaction-set/940) Request shipping from a warehouse
  • [945](https://www.stedi.com/edi/x12/transaction-set/945) Communicate fulfillment to a seller
  • [944](https://www.stedi.com/edi/x12/transaction-set/944) Indicate receipt of a stock transfer shipment
  • [943](https://www.stedi.com/edi/x12/transaction-set/943) Stock transfer shipment notification
| | **Retail** |
  • [850](https://www.stedi.com/edi/x12/transaction-set/850) Send a purchase order to a retailer
  • [855](https://www.stedi.com/edi/x12/transaction-set/855) Send a purchase order acknowledgment back to a retailer
  • [856](https://www.stedi.com/edi/x12/transaction-set/856) Send a ship notice to a retailer
  • [810](https://www.stedi.com/edi/x12/transaction-set/810) Send an invoice
| | **Healthcare** |
  • [834](https://www.stedi.com/app/guides/view/hipaa/benefit-enrollment-and-maintenance-x220a1/01GRYB6D6RAWSG8ATBD6GXM13C) Send benefits enrollments to an insurance provider
  • [277](https://www.stedi.com/app/guides/view/hipaa/claim-acknowledgement-x214/01HACJ4MNFWR3GV3BCVAMG04PK) Indicate the status of a healthcare claim
  • [276](https://www.stedi.com/app/guides/view/hipaa/claim-status-request-x212/01GRYB6A4XEJQ61Y2K2KT606E5) Request the status of a healthcare claim
  • [278](https://www.stedi.com/app/guides/view/hipaa/health-care-services-review-information-review-x217/01GRYB6BA03R4N4W2VZ7EY927T) Communicate patient health information
  • [835](https://www.stedi.com/app/guides/view/hipaa/health-care-claim-paymentadvice-x221a1/01GRYB6DS30MGXWBPFZCM3695E) Make a payment and/or send an Explanation of Benefits (EOB) remittance advice
| ## EDI Standards A few technical standards have been created since the introduction of EDI including X12 in North America and EDIFACT which is prevalent throughout Europe. Standards bodies make changes over time and version releases with names like “Release 004010”. These standards do not exist to solve all of the problems of B2B transactions. Instead they exist to allow a trading partner to understand each of its trading partner's internal syntax and vocabulary. Standards such as X12 and EDIFACT provide highly structured, opinionated alternatives intended to reduce the surface area of knowledge required to successfully integrate with trading partners. All documents conforming to a given standard follow that standard’s syntax, allowing an adoptee of the standard to work with just one syntax for all trading partners who have also adopted that syntax. ## How is EDI transmitted? EDI can be transmitted using various protocols, but these are the most common ways to exchange files with your trading partners. ### SFTP/FTPS SFTP (SSH File Transfer Protocol) and FTPS (File Transfer Protocol Secure) are both secure file transfer protocols used to transmit files between computers over a network. * SFTP is a secure version of the FTP protocol, providing encryption and authentication using the Secure Shell (SSH) protocol. It encrypts both the data being transmitted and the commands used to perform file operations. * FTPS is an extension of the FTP protocol that adds support for Transport Layer Security (TLS) or Secure Sockets Layer (SSL) encryption. It can use either implicit SSL, where the entire session is encrypted from the start, or explicit SSL, where the client requests a secure connection after connecting to the server. You can set up your own SFTP/FTPS server for your trading partner to connect to, or (common with large trading partners) you will need to connect to your trading partner's remote SFTP/FTPS server to exchange files. ### AS2 AS2, or Applicability Statement 2, supports encryption of the data being exchanged and uses digital signatures to verify the authenticity and integrity of the data. AS2 also supports MDN (message disposition notification), a way for your partner to acknowledge that they have received your message. Some partners may require that you request and accept an MDN response, send MDN responses, or both. ### Value Added Network (VAN) A VAN acts as an intermediary between trading partners. Instead of establishing a direct connection with your trading partners, you and your partners would connect to a VAN, and the VAN would broker the connection for you. It is not a requirement for you and your partners to use the same VAN — this is called a "VAN to VAN interconnect." VANs often provide additional services on top of basic message routing. These may include data translation between different EDI standards, data encryption for security, data archiving, auditing, and tracking of transactions. # Element data types in X12 EDI All [elements in X12](https://www.stedi.com/edi/x12-008010/element) have a specific data type: elements can be a string (i.e., alphanumeric), number, decimal, date, time, code, or binary. These data types dictate the kind of data that can be sent in a specific element and how it should be treated by external systems ingesting the EDI. ## String/Alphanumeric (AN) Elements with the `string` data type are symbolized by the code `AN`. Strings may contain any sequence of characters, including letters, digits, spaces, punctuation marks, spaces, tabs, and/or special characters. Typically, elements with the string data type are used in free-form fields, where the element name or description explains what information should be contained in the element, and how to interpret it. While elements with a string data type can support any character, they must not contain the element separator (often `*`), sub-element separator (often `^` or `:`), or segment terminator (often `~`) specified in the envelope; those are reserved solely for those functions. Furthermore, for any EDI transaction that specifies a release character in the `ISX` segment (v7040 or later), you cannot use that release character in any element. **Examples of `string` elements include:** * Red * Working hours: from 9AM to 5PM * New York * X253N0123 ## Numeric (N0, N2, N4, N6) Elements with the `numeric` data type are symbolized by `N`. All elements with a numeric data type must contain only digits and an optional minus (-) sign to indicate a negative value. The `N` indicates that the data type is numeric, and the `0`, `2`, `4`, or `6` indicate the number of implied decimal positions. `N0` implies the number is an integer (i.e., whole numbers), `N2` implies the number contains two decimal positions, `N4` implies the number contains four decimal positions, and `N6` implies the number contains six decimal positions, For example, if a number is sent in an element with the data type `N0`, it should be interpreted as a whole number, exactly as it is shown. **Examples of `N0` elements include:** * 1 * 100 * \-645 * 812 If a number is sent in an element with the data type `N2`, it should be interpreted as if it has two decimal places. **Examples of `N2` elements include:** * 123.45 would be sent as 12345 * \-5 would be sent as -500 * 100 would be sent as 10000 In practice, the `N2` data type is often used in elements that describe a monetary amount. For example, the [610 (Amount)](https://www.stedi.com/edi/x12-008010/element/610) element is used in the [TDS01](https://www.stedi.com/edi/x12-008010/segment/TDS) to represent the invoice total amount, and has a data type of `N2`. This implies the value of `TDS01` has two decimals. For example: `TDS*1000` implies a dollar value of `$10`, not `$1000`. ## Decimal number (R) Elements with the `decimal number` data type are symbolized by the code `R`. In an element with a decimal data type, decimals are optional for all integers, but are required for all fractional values. Decimal numbers also support a leading minus (-) sign, if needed, whereas the absence of a minus sign implies a positive value. Therefore, the plus sign (+) should not be transmitted. The minus sign and the decimal point are not counted when determining the length of the data element. Additionally, all leading zeros in an element with a decimal number type should be suppressed, unless needed to satisfy minimum length requirements. **Examples of `decimal` elements include:** * 12.345 * 2000 * 765.000 * \-95 ## Dates (DT) Elements with the `date` data type are symbolized by the code `DT`. Based on the X12 version, data formats are treated differently. Before v4010, all dates were in the `YYMMDD` format, where `YY` represents the last two digits of the calendar year, `MM` represents the month (01 to 12), and `DD` represents the day of the month (01 to 31). **Examples of dates in `YYMMDD` format include:** * `980127`, which indicates `January 27th, 1998` * `220815`, which indicates `August 15th, 2022` Starting from v4010, all dates are represented in the `CCYYMMDD` format, where `CC` represents the first two digits of the calendar year, `YY` represents the last two digits of the calendar year, `MM` represents the month (01 to 12), and `DD` represents the day of the month (01 to 31). **Examples of dates in `CCYYMMDD` format include:** * `20230202`, which indicates `February 2nd, 2023` * `20220120`, which indicates `January 20th, 2022` **Note:** The [ISA09 (interchange date)](https://www.stedi.com/edi/x12-008010/segment/ISA) only supports the `YYMMDD` date format, regardless of which X12 version is used. ## Time (TM) Elements with the `time` data type are symbolized by the code `TM`. Time in the X12 standard is expressed in a 24-hour clock format (e.g.,`HHMM`, `HHMMSS`, `HHMMSSD`, or `HHMMSSDD`). `HH` is the numeric expression of the hour (00 to 23), `MM` is the numeric expression of the minute (00 to 59), `SS` is the numeric expression of the second (00 to 59), and `DD` is the numeric expression of the decimal seconds. Decimal seconds are expressed as follows: `D` = tenths (0 to 9) and `DD` = hundredths (00 to 99). **Examples of `time` elements include:** * `1845`, which represents `18:15` in `HHMM` format * `091530`, which represents `09:15:30` in `HHMMSS` format * `10220302`, which represents `10:22:03:02` in `HHMMSSDD` format **Note:** Time elements are often accompanied by another element in the same segment, indicating which timezone the time is in. ## Identifier (ID) Elements with the `identifier` data type, sometimes referred to as a `code`, are symbolized by the code `ID`. An element with an `ID` data type must always contain a value from a predefined list of values that is maintained by X12, other bodies that are recognized by X12, or are universally known (e.g., Standard Carrier Alpha Codes (SCACs), or state/province codes). The intent of the identifier data type is to allow computers to validate data elements based on a standard list of codes, without having to agree upon the meaning of each code. For the elements that contain a predefined list of X12 identifiers, each one has a code and a description (e.g., `ST` and `Ship To`). An *extended code definition*, which provides additional information to help explain the meaning of the code, may also be supplied in addition to the identifier description. **Examples of pre-defined X12 `identifier` codes include:** * `ST` - ship to * `Z7` - mark for party * `YC` - bail payor In addition to elements with a predefined list of X12 identifier codes, there are several elements that have the `ID` data type without a predefined list. Here are some examples: * Element [156 (State or province code)](https://www.stedi.com/edi/x12-008010/element/156) should contain the two-digit code of a US state (e.g., `CA` for California), Canadian provinces (e.g.,`ON` for Ontario), or any other state/province/region code specific for a given country (must be exactly two characters). * Element [26 (Country Code)](https://www.stedi.com/edi/x12-008010/element/26) should contain a two-letter country code defined by ISO 3166 (e.g., `US` for the United States of America, `IN` for India). * Element [140 (SCAC)](https://www.stedi.com/edi/x12-008010/element/140) should contain a two- to four-character code that represents a carrier, as defined by the National Motor Freight Traffic Association (NMFTA). However, in practice, SCACs are often sent as mutually agreed upon values. While X12 is standardized, in practice, many trading partners will deviate from these predefined lists. X12 provides a mechanism for doing this, by supporting “mutually-defined” codes, signified by the codes `Z`, `ZZ`, or `ZZZ`. While mutually-defined codes are available, some trading partners might choose to “break” the X12 standard by utilizing their own custom codes and descriptions in their implementation guides. Lastly, some trading partners will interpret the predefined codes differently (e.g., they will use the `WH` (warehouse) qualifier code, as opposed to the `SF` (ship from) code). ## Binary (B) Elements with the `binary` data type are symbolized by the code `B`. A binary data element contains a sequence of bytes. Those bytes may include characters that normally have special meaning, like the segment separator, or the element separator. For that reason, binary data isn’t parsed like the rest of the X12 document. Instead, binary data always comes with a length, so that it’s clear where the binary data ends. There are only a few segments with a binary data element. * [BIN](https://www.stedi.com/edi/x12/segment/BIN) is used to transfer files. It always comes as part of a loop that also include the [EFI](https://www.stedi.com/edi/x12/segment/EFI) segment. `EFI` contains the metadata of the file, `BIN` contains the contents. * [BDS](https://www.stedi.com/edi/x12/segment/BDS) (v4020 and up) is also used to transfer files, but it’s paired with [OOI](https://www.stedi.com/edi/x12/segment/OOI) instead of `EFI`. `OOI` is a more flexible way to encode a file’s metadata. Unlike `BIN`, `BDS` includes an element that tells you how the binary data is encoded, for example base64, uuencoding, no encoding, etc. * [S3S](https://www.stedi.com/edi/x12/segment/S3S) and [S4S](https://www.stedi.com/edi/x12/segment/S4S) are used for sending data securely. They both use binary (v4020 and up) to send encrypted and/or compressed data. Stedi supports reading and writing binary encodings that are valid UTF-8 strings such as ASCII and Base64. It does not support unfiltered binary data. # Element Requirements in X12 EDI When an [element](https://www.stedi.com/edi/x12-008010/element) is in the context of a [segment](https://www.stedi.com/edi/x12-008010/segment), the X12 standard specifies three types of element requirements: mandatory, optional, or conditional. In addition to the requirements given by X12, trading partners will often deviate slightly from the standard to suit their business needs. This is both expected and valid. Trading partners share these requirements as *implementation guides*, usually via PDF. Most X12 implementation guides used in the industry were built using a tool called SpecBuilder, which creates a standard PDF format. We will use SpecBuilder PDFs and their terminology to explain element requirements below, but your trading partner might send these requirements in different format (e.g., CSV, Word, custom PDF). In these implementation guides, the element requirements given by X12 are found in a column called *Requirement* (or *Req* for short). The *Req* column displays these requirements as `M` for mandatory, `O` for optional, and `C` or `X` for conditional. If a trading partner deviates from the specifications given by X12, those deviations are usually found in a column called *Usage* or *Attributes*, and they use a different syntax, like `Must use`, `Used`, and `Dependent`. ## X12 types ### Mandatory Mandatory elements are marked with an `M` in most implementation guides, but `R` (required) is used as well. If an element is defined as mandatory in a segment, then you cannot send X12 data without it. In most cases, transactions that are missing mandatory elements will either be stopped by the sender or rejected by the recipient. For example, the `BIG01` (Invoice Date) and the `BIG02` (Invoice Number) in the [BIG segment](https://www.stedi.com/edi/x12-008010/segment/BIG) used in all [X12 810 Invoices](https://www.stedi.com/edi/x12/transaction-set/810) are mandatory elements. You cannot send an invoice without the invoice number and date. Image of Mandatory usage in the BIG Segment ### Optional Optional elements are marked with an `O` in most implementation guides. These elements sometimes carry additional information in the notes section of the PDF, such as when the element should be used. If an element is marked as optional, it can be omitted in the data and the transaction would still be valid. For example, the `BIG03` (Purchase Order Date) and `BIG04` (Purchase Order Number) in [X12 810 Invoices](https://www.stedi.com/edi/x12-008010/810) are optional elements. According to X12, you can send an invoice without the corresponding purchase order number and date, and it would still be a valid transaction. Image of Optional usage in the BIG Segment ### Conditional Conditional elements, marked with either a `C` or an `X`, are a special case. Their usage depends on the other elements within the same segment. In some situations these elements might be mandatory, and in others – optional. Whenever there is an element marked with a `C` or an `X`, there will be a corresponding *Syntax Rules* block on the same page. For example, on the `DTM` segment page below, the syntax rules appear below the last element definition. Image of Conditional usage in the DTM segment In order to understand how and when to use an element that is marked as conditional, you first need to understand the X12 syntax rule used. Every syntax rule begins with an identifier: `P`, `R`, `E`, `C`, or `L`. The identifier is followed by two or more elements involved in the condition, where each element occupies two digits (e.g., `01`, `05`, `11`). **Conditional rule definitions:** | Letter | Name | Condition | Example | | ------ | ---------------- | ----------------------------------------------------------------------------------------- | ------- | | P | Paired | If the first element is present, then all the other elements must be present. | P0102 | | R | Required | At least one of the elements must be present. | R020304 | | E | Exclusive | Only one of the elements may be present. | E0305 | | C | Conditional | If the first element is present, then all the other elements must be present. | C0102 | | L | List conditional | If the first element is present, then at least one of the other elements must be present. | L010308 | ## Trading partner specific element requirements The element requirements defined by the X12 standard dictate which elements are optional, mandatory, or conditional when used in a segment. However, most businesses do not use all the elements in the standard - and for those that they use, they often need to change their requirements. As such, they use the elements, and change their requirements, to best serve their business requirements. For example, your trading partners may decide that some elements—whether optional or conditional as per the standard—must be present in the data (e.g., are mandatory). On the other hand, this does not work in reverse; according to the X12 standard, you cannot mark elements that are mandatory as optional or conditional in your guide. In practice, some businesses break the X12 standard and ask trading partner's to conform to their specification nonetheless. When a trading partner deviates from the base X12 specification, their implementation guide will usually contain a column titled *Usage* or *Trading Partner Name Requirements*. Instead of using the typical `M`, `O`, `C`, and `X` syntax, they will use other terms like `Must Use`, `Used`, or `Dependent`. Below is an example of an [MEA (Measurement) segment](https://www.stedi.com/edi/x12/segment/MEA) with multiple elements and composite elements which are considered optional or conditional by the X12 v4010 standard, but all marked as `Must use`: Image of Trade Partner Deviating from the spec for MEA Segment Below is a table which explains the relationship between the customer defined usage and standard X12 codes: | Customer Defined Usage | Equivalent X12 type | Definition | | ---------------------- | ------------------- | ----------------------------------------------------------------------- | | Must Use | M | May be sent on the EDI transaction | | Used | O | May be sent on the EDI transaction | | Not used | N/A | Must not be sent on the EDI transaction | | Recommended | O | Should be sent on the EDI transaction | | Not Recommended | N/A | Should not be sent on the EDI transaction | | Future | N/A | Should not be sent on the EDI transactions, but reserved for future use | | Dependent | C or X | Conditional based on syntax rules | When you are building EDI integrations, make sure you pay close attention to element requirements, and how they deviate from the base X12 standard. # Relational conditions in X12 EDI All [elements](https://www.stedi.com/edi/x12-008010/element) in the X12 standard can be marked as mandatory (`M`), optional (`O`), or Conditional (`C` or `X`). If an element is marked as conditional, its usage depends on the presence (or absence) of other elements in the same segment. These relational conditions are described using a specific X12 syntax and are usually found in the implementation guide shared between trading partners. While relational conditions were touched on briefly in [Element Requirements in X12 EDI](https://www.stedi.com/edi/essentials/x12/elements/element-requirements), this article provides a more in-depth analysis of the subject. ## Overview If an element is marked as conditional, that condition is governed by the associated syntax rule. Every syntax rule begins with an identifier: `P`, `R`, `E`, `C`, or `L`. Each identifier is then followed by two or more elements involved in the condition, where each element is referred to by its position in the segment (e.g., `01`, `05`, `11`), and each element position occupies two digits. For a given segment, there can be one or more syntax rules, and a single element can be associated with one or more syntax rules inside a single segment. The table below describes the meaning of each rule: | Letter | Name | Condition | Example | | :----- | :--------------- | :---------------------------------------------------------------------------------------- | :------ | | P | Paired | If the first element is present, then all the other elements must be present. | P0102 | | R | Required | At least one of the elements must be present. | R020304 | | E | Exclusive | Only one of the elements may be present. | E0305 | | C | Conditional | If the first element is present, then all the other elements must be present. | C0102 | | L | List conditional | If the first element is present, then at least one of the other elements must be present. | L010308 | ## Paired (P) If a syntax rule starts with `P`, it is a *paired condition*. This condition means that if any element in the rule is present in the segment, then all the other element(s) in the rule must be present as well. A typical example of when a paired syntax rule is used is when one element describes the meaning of another. For example, elements [N103 (Identification Code Qualifier)](https://www.stedi.com/edi/x12-008010/element/66) and [N104 (Identification Code)](https://www.stedi.com/edi/x12-008010/element/67) are always paired, which is indicated by the syntax rule `P0304`. This means that if one of them is present, then the other must be present as well. These two elements are paired because only sending one element would not make sense without the other. In this example, the `N103` “qualifies” the `N104` – it explains who or what entity assigned the identification code. Providing just the qualifier or just the identification code does not provide a trading partner with enough information, so they must be sent together. **The description of the paired syntax rule always follows this format:** * If either \{XX}, \{YY},..., or \{ZZ} is present, then the other is required. Image of Paired syntax rule in the N1 Segment ## Required (R) If a syntax rule starts with `R`, it is a *required condition*. This condition means that at least one of the elements listed in the rule must be present in the segment. Typically, a required syntax rule is used when there are multiple positions within a segment to provide the necessary information, but not all elements are needed to communicate that information. A good example of a required syntax rule is in the [TXI (Tax Information) segment](https://www.stedi.com/edi/x12-008010/segment/TXI). This segment contains the R020306 syntax rule, which indicates that at least one of `TXI02` (Monetary Amount), `TXI03` (Percent), or `TXI06` (Tax Exempt Code) is required. This means that you can provide the tax amount (e.g., \$18.65), the tax percent (e.g., 12%), the code that explains tax exemption (e.g., `F`, Exempt from Goods and Services Tax), or all three - but you have to supply at least one, otherwise it will not convey enough information. **The description of the required syntax rule always follows this format:** * At least one of \{XX}, \{YY},..., or \{ZZ} is required. Image of Required syntax rule in the TXI Segment ## Exclusive (E) If a syntax rule starts with `E`, it is an *exclusive condition*. Only one of the elements in the syntax rule may be present, but no others. Typically, an exclusive syntax rule is used when there are multiple elements in a segment that, if sent together, would cause a conflict in interpretation. A good example of an exclusive syntax rule is in the [G72 (Allowance or Charge) segment](https://www.stedi.com/edi/x12-008010/segment/G72). This segment contains a `G7205` (Allowance or Charge Rate), a `G7208` (Allowance or Charge Total Amount), and a `G7209` (Allowance or Charge Percent). Because an allowance or charge can only be indicated as a unit rate, a total amount, or a percent (but not as more than one), these elements cannot be sent together. **The description of the exclusive syntax rule always follows this format:** * Only one of \{X}, \{Y},..., or \{Z} may be present. Image of Exclusive syntax rule in the G72 Segment ## Conditional (C) If a syntax rule starts with `C`, it is a *conditional rule*. If the first element listed in the rule is present, then the subsequent elements must be present as well. Typically, conditional rules are used because the first element listed in the rule cannot stand on its own; It is only useful when the subsequent elements are present. An example of a conditional rule is when there are two elements in the rule, and the first element listed provides added context to the second element. This is different from a paired syntax rule because the second element listed could stand on its own without the first element, whereas the first cannot. For example, the [DTM (Date/Time Reference) segment](https://www.stedi.com/edi/x12-008010/segment/DTM) has a `C0403` syntax rule. This rule states that if the `DTM04` (Time Code) is present then the `DTM03` (Time) is required. A time code in this case is synonymous with “time zone” (e.g., PT, ET, IST, etc.). As such, if the time code is present, but no time is present, then the time code is useless. However, if the `DTM03` (Time) is present, then the time code is not necessarily required (but in this case, could be ambiguous). **The description of the conditional syntax rule always follows this format:** * If \{X} is present, then \{Y} is required. Image of Conditional syntax rule in the DTM Segment ## List conditional (L) If a syntax rule starts with `L`, it is a *list conditional rule*. If the first element in the rule is present, then at least one of the other elements listed in the rule is required. There must always be three or more elements in a list conditional rule, otherwise, a conditional syntax rule should be used. Typically, list conditional rules are used because the first element cannot stand on its own, and there are multiple other elements in the segment that can be used to provide the necessary information. For example, the [ITD (Terms of Sale/Deferred Terms of Sale) segment](https://www.stedi.com/edi/x12-008010/segment/ITD) contains the `L03040513` rule. This means that if the `ITD03` (Terms Discount Percent) is present, then at least one of `ITD04` (Terms Discount Due Date), `ITD05` (Terms Discount Days Due), or `ITD13` (Day of Month) is required. Because the terms discount percent given in the `ITD03` needs an associated date, then one of the terms (i.e., discount due date, the terms discount days due, or the day of the month) is required in order to convey the information necessary to the recipient. As with conditional rules, the presence of `ITD04`, `ITD05`, or `ITD13` does not make `ITD03` required. **The description of the conditional syntax rule always follows this format:** * If \{X} is present, then at least one of \{Y},..., or \{Z} is required. Image of List conditional syntax rule in the ITD Segment # What is an element in X12 EDI? [Elements](https://www.stedi.com/edi/x12-008010/element) in X12 EDI are the primary source of information exchanged in an EDI transaction. [Segments](https://www.stedi.com/edi/x12-008010/segment) logically group elements together in order to convey specific information. You will always see elements inside of a segment, and elements are separated from the segment and other elements by delimiters (e.g., `*`, `|`, etc.). Outside the context of a segment, the X12 standard defines an ID, a name, description, data type, and min and max length for every element. These element attributes are fixed; they do not change, regardless of what segment the element is found in. When an element is in the context of a segment, the X12 standard provides additional attributes, such as the element’s position and its requirement. These attributes are variable; they change based on which segment the element is contained in. For example, each element in the [BEG segment](https://www.stedi.com/edi/x12-008010/segment/BEG) below has its own fixed attributes, and then additional attributes based on the fact they are used in the `BEG` segment. For example, the [373 Date element](https://www.stedi.com/edi/x12-008010/element/373) always has the `date` data type and a min and max length of eight characters; but when it is used in the fifth element of the `BEG` segment (e.g., the `20220610` below), it is always mandatory. `BEG*00*NE*080032**20220610~` Image of BEG segment ## Element attributes ### IDs Each element is given a unique ID that can be one to four characters in length. There are more than 2,000 unique elements in the X12 EDI standard. For example, the `Purchase Order Type Code` element has the ID `92`, whereas the Date element has the ID `373`. The IDs of *simple* *elements* are numeric, but *composite data elements* are prefixed with a `C`, and elements found in interchange segments are prefixed with `I`. You can see the full list of elements and their IDs [here](https://www.stedi.com/edi/x12/element). Image of 373 Date element ### Names Each element is given a name, which is a short, generic description of what data the element represents. For example, the name of the `324` element is `Purchase Order Number` and the name of the `100` element is `Currency Code`. While the element is given a unique element ID, in practice, the element name is used for identifying the element, not the ID. You can see the full list of elements and their names [here](https://www.stedi.com/edi/x12/element). Image of 324 Purchase Order Number element ### Descriptions and semantic notes In addition to the element name, X12 provides a longer description to explain what the element represents and how it is used. For example, the `373` Date element has the following description: date expressed as `CCYYMMDD` where `CC` represents the first two digits of the calendar year. When an element is in the context of a segment, X12 will occasionally provide semantic notes, which explain how that element is used specifically inside of the segment. For example, the `373` Date element has an extra note when it is in the `BEG` segment: in the `BEG`, the Date element (`BEG05`) is the date assigned by the purchaser to purchase order. Image of 373 Date element and semantic notes ### Data types All elements in X12 have a specific data type: elements can be a string (i..e., alphanumeric), number, decimal, date, time, code, or binary. These data types dictate the kind of data that can be sent in a specific element and how it should be treated by external systems ingesting the EDI. **Note:** Element separators (often `*`), sub-element separators (often `^` or `:`), and segment terminators (often `~` or `\n`) cannot be used in any elements, regardless of data types. | **Data type** | **Acronym** | **Description** | **Example** | | --------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | String / Alphanumeric | AN | May contain any alphanumeric characters, including letters (upper & lowercase), numbers, punctuation marks, spaces, and more. |
  • Red
  • Working hours: 9 a.m. to 5 p.m.
  • X355SNHM
| | Number | N0, N2 | Must contain only digits (no decimals), and can contain a minus sign for negative values. The N indicates it is a number, and `0` or `2` indicates the number of implied decimal points. N0 is used for integers, and N2 is used to imply two decimal points. | N0
  • 1
  • -645
N2
  • 81342 (equal to 813.42)
  • -42 (equal to -0.42)
| | Decimals | R | May contain numbers with decimal points (if needed) and a minus sign for negative values. |
  • 12.345
  • -95
  • 765.00
| | Dates | DT | Date formats in X12 depend on trading partner specs and the version used. X12 versions before v4010 used YYMMDD format. After v4010, CCYYMMDD format is preferred, where CC represents the first two digits in the calendar year. ISA-09 (interchange date) is an exception and uses YYMMDD. | YYMMDD
  • 980127 (`27 Jan 1998`)
CCYYMMDD
  • 19980127 (`27 Jan 1998`)
  • 20220926 (`26 Sep 2022`)
| | Time | TM | Time is always expressed in 24-hour clock time as follows: HHMM, or HHMMSS, or HHMMSSD, or HHMMSSDD, where H = hours (00-23), M = minutes (00-59), S = integer seconds (00-59) and DD = decimal seconds; decimal seconds are expressed as follows: D = tenths (0-9) and DD = hundredths (00-99). Time elements are usually followed by a qualifier code representing time zone. | HHMM
  • 1315 (13:15)
HHMMSS
  • 131545 (13:15:45)
HHMMSSDD
  • 13:15:45:233
| | Codes | ID | Most elements with "code" data types have a list of valid codes defined by the X12 standard. These codes are usually "qualifiers" or "values" that are shorthand for a value. Codes are never longer than 4 digits. Some codes are not provided by X12, like 156 (state or province code) or 24 (equipment type). | Qualifiers
  • ZZ (mutually defined)
  • SF (ship from)
Values
  • KG (kilograms)
Non-X12 codes
  • US (United States)
  • FHD (FedEx SCAC code)
| | Binary | B | Elements with the binary data type may contain binary data (i.e., a string of octets which can assume any binary pattern from hexadecimal 00 to FF. Note: The maximum length is 15 characters for binary data. Only the BIN and BDS segments support elements with a binary data type. |
  • TG9yZW0gSXBzdW0=
| To learn more about element data types in X12 EDI, [click here](https://www.stedi.com/edi/essentials/x12/elements/element-data-types). ### Length (min/max) Each element is given a minimum and maximum length that they need to adhere to, as per the X12 standard. The minimum and maximum length can vary from element to element. For example, some elements have fixed lengths like `NTE01` (Note Reference Code) which have a minimum and maximum length of three characters. On the other hand, some elements can contain a wide range of characters, like `NTE02` (Description), which supports a minimum of one character and a maximum of 80. For elements with the decimal data type (`R`), the count of characters does not include the optional decimal point, minus sign, or trailing exponent indicator `E`. **Note:** If an element is optional and is not used in a segment, the length restrictions do not apply. Image of Note Reference Code elements ### Position When an element is used in a segment, it occupies a position in that segment. The X12 standard defines what element is used in every position of a segment. While elements can be referred to by their ID and name (e.g., the `373` Date element in the `BEG`), in-practice element positions are referred to by the segment acronym (e.g., `TDS`), followed by the position of the element in the segment (e.g., `01`). For example, the second element in the `TDS` is `TDS02`, and so on. This is useful for communicating trading-partner requirements, as you can refer to an element as the *TDS05*. The same element can be found multiple times, in different positions of a single segment. The position, accompanied by semantic notes, determines how to use that element. For example, the element `610` (Amount) is used four times in the `TDS` segment, where the `TDS01` is the total amount of the invoice, and the `TDS04` indicates the total amount of terms discount. **Note:** If an element is not present, it still occupies a position. Image of TDS segment ### Requirements When an element is in the context of a segment, the X12 standard specifies three types of element requirements: mandatory, optional, or conditional. In addition to the requirements given by X12, trading partners will often deviate slightly from the standard to suit their business needs. * **Mandatory**: Elements marked as mandatory (`M`) must be present in the segment. * **Optional**: Elements marked as optional (`O`) may be present in the segment. * **Conditional**: The presence of an element in a segment marked as conditional (`C` or `X`) is dependent on the relational condition syntax rule used. To learn more about element requirements in X12 EDI, [click here](https://www.stedi.com/edi/essentials/x12/elements/element-requirements). ### Composite & component elements A composite element contains a collection of component elements (also known as sub-elements). Component elements are functionally the same as the simple elements we explored above, only they have the composite element as the parent, not the segment. Composite elements also have their own IDs, which begin with `C`. For example, `C040` (Reference Identifier) is a composite data element. For composite elements, the same position notation (e.g., `REF04`) is used, however, for component elements, the position is given as the name of their parent composite element + `C` + position. For example, the second component element in `REF04` would be referred to as `REF04C02`. # X12 HIPAA X12 HIPAA is the common name for the set of specifications businesses use to transmit healthcare transactions in the United States. A *transaction* is an electronic exchange of information between two parties to carry out financial or administrative activities related to healthcare. For example, a healthcare provider like a hospital may send a claim to a health plan to request payment for medical services. X12 HIPAA is a narrower subset of the X12 standard. The name refers to the detailed specifications that the X12N Insurance subcommittee have defined. The official term for these specifications is a Technical Report Type 3 (TR3). More commonly, they are called X12 HIPAA implementation guides, though regulators call them federally-mandated operating rules. ## Where can I find X12 HIPAA specifications? The [Stedi Network](https://www.stedi.com/edi/network) has [Stedi guides](https://www.stedi.com/docs/edi-platform/guides/index) for every X12 HIPAA transaction set. Stedi guides are interactive, machine-readable EDI specifications that let you instantly validate EDI test files. You can import any HIPAA guide into your Stedi account and use it to validate and generate EDI. Learn more about [HIPAA compliance on Stedi](/security-and-compliance/hipaa). ## Is my trading partner's companion guide the same as an X12 HIPAA specification? No. A companion guide such as [Anthem's 270/271 companion guide](https://www.anthem.com/docs/public/inline/EDI_CA_00021.PDF) is only an addendum and does not contain the complete information required to understand the specification. To create a valid transaction, you also need the information contained in the X12 HIPAA implementation guide. Generally, you start with the X12 HIPAA implementation guide and then customize it further using the information in the companion guide. Companion guides are allowed to be *more* restrictive than the X12 HIPAA implementation guides, but they cannot be *less* restrictive. For example, if the X12 HIPAA implementation guide says that a given field is required, a companion guide provided by a healthcare plan operator cannot say that the field is optional. By the same token, the X12 HIPAA implementation guides are always more restrictive than the base X12 Release 5010 specification, and they can never be less restrictive. ## Does every healthcare company use the same specification? No. There are two reasons why healthcare companies don't share the exact same specifications. First, HHS so far has only mandated the strict use of X12 HIPAA implementation guides (also called operating rules) for a subset of transactions. Refer to the [Operating Rules Mandate](https://www.caqh.org/core/operating-rules-mandate) for complete details. So, while many companies may choose to adopt the X12 HIPAA implementation guides as a restriction above and beyond the base X12 Release 5010 standard, X12 HIPAA is not strictly required for all transaction sets. | Transaction Name | X12 Transaction Set | Federally Mandated Operating Rules | | ---------------------------------------------------------------------------------- | ------------------- | ---------------------------------- | | Eligibility and benefit verification | 270/271 | Yes | | Claim status inquiry and response | 276/277 | Yes | | Claim payment (EFT) / Electronic remittance advice (ERA) | 835 | Yes | | Prior Authorization and referrals / Referral certification | 278 | No | | Premium payment/explanation (employer) | 820 | No | | Enrollment/disenrollment in a health plan | 834 | No | | Health claims (institutional, professional, and dental) / coordination of benefits | 837 | No | Second, even for transaction sets that have federally mandated operating rules, like the 270 and 271, companies are permitted to implement further constraints. These additional constraints are provided in a companion guide, such as the one Anthem provides for its [270/271](https://www.anthem.com/docs/public/inline/EDI_CA_00021.PDF). ## Why does healthcare use X12 HIPAA? The United States Department of Health and Human Services (HHS) originally chose X12 as the mandated standard. Standardizing on X12 meant that all parties would use a common transaction structure, which would serve to minimize the industry's proliferation of multiple formats. ### X12 allowed too much flexibility While HHS found that adopting X12 decreased administrative burden for parties by creating greater uniformity, the flexibility of the X12 standard meant that each health plan used the transaction set standards in different ways. Although the X12 standard constrained the data elements that could be used, an organization was free to impose additional constraints required by their business flow and operations, both in terms of technical constraints and business semantics. For example, different health plan operators may have allowed for a different number of transactions to be submitted in a single file. They may also have had different opinions about which specific data elements are required for each transaction. This led each health plan operator to create a companion guide, typically a PDF, that described their unique implementation of the X12 transaction sets. This required trading partners (the providers) to adhere to different transaction implementation rules for each plan operator, subverting the original goal of administrative simplification. ### X12 HIPAA reduces ambiguity Congress passed laws in 2010 ([Public Law 111-148](https://www.govinfo.gov/content/pkg/PLAW-111publ148/pdf/PLAW-111publ148.pdf) | [Public Law 111-152](https://www.govinfo.gov/content/pkg/PLAW-111publ152/pdf/PLAW-111publ152.pdf)) requiring HHS to "adopt a single set of operating rules for each transaction\[...]with the goal of creating as much uniformity in the implementation of the electronic standards as possible." The laws mandate that these operating rules "describe all data elements (including reason and remark codes) in unambiguous terms, require that such data elements be required or conditioned upon set values in other fields, and prohibit additional conditions (except where necessary to implement State or Federal law, or to protect against fraud and abuse)." Essentially, Congress mandated that not only would the healthcare industry needed to use a very specific subset and configuration of the values allowed by X12 in order to "reduce ambiguities currently permitted by the standard." ([Rule by Health and Human Services Department](https://www.federalregister.gov/documents/2011/07/08/2011-16834/administrative-simplification-adoption-of-operating-rules-for-eligibility-for-a-health-plan-and)). As a result, the healthcare industry worked with X12 to form the X12N Insurance committee, which created a detailed specification for each transaction set. These specifications are formally called a Technical Report Type 3 (TR3). The series of TR3s produced by the X12N Insurance committee is what's commonly known as X12 HIPAA. # Segment repetition in X12 EDI" Sometimes a [segment](https://www.stedi.com/edi/x12-008010/segment) in a transaction set can be repeated. This usually shows up in implementation guides as the `Max Use` of a segment. Image of max use segment * `1` means that the segment cannot be repeated. * `>1` means that the segment can be repeated an infinite number of times. * Any other number means the segment can be repeated at most that number of times. The X12 standard defines the repetition for each segment, but your trading partner may deviate from the standard in their implementation guide to suit their business needs. In that case, you should follow the implementation guide. # Qualifiers You’ll see segment repetitions most often when the segment has a qualifier. A qualifier determines the meaning of a segment. For example, the [DTM segment](https://www.stedi.com/edi/x12-008010/segment/DTM) contains a date and it uses a qualifier to tell you if it’s a shipping date, a delivery date, a blind date, etc. It often makes sense to have multiple dates, so the `DTM` segment can be repeated. ``` DTM*011*20220921~ DTM*017*20220922~ ``` In the example above, the first segment is the shipping date and the second segment is the estimated delivery date. In a situation like this, the implementation guide will often deviate from the X12 standard. The standard may say that the `DTM` segment can be repeated, say, 300 times, but if your trading partner only accepts a shipping date and an estimated delivery date, they may set a maximum of 2 repetitions. ## Multiple qualifiers In most cases, repeated segments do not use the same qualifier more than once. After all, it wouldn’t make much sense to have a single shipment with multiple shipping dates. However, some segments have multiple qualifiers. For example, the [MEA segment](https://www.stedi.com/edi/x12-008010/segment/MEA) represents a measurement. The first qualifier tells you what kind of measurement you’re dealing with, say a weight. The second qualifier tells you what kind of weight. The following example includes both a gross weight and a net weight. ``` MEA*WT*G*1023*LB~ MEA*WT*N*1000*LB~ ``` ## Repeatable qualifiers There are also cases where it’s perfectly valid to repeat the same qualifier. For example, a container may have multiple seals. You can use a separate [REF segment](https://www.stedi.com/edi/x12-008010/segment/REF) for each seal and they’ll all have the same qualifier. ``` REF*SN*A999001~ REF*SN*A999002~ REF*SN*A999003~ ``` # Long data Every segment has a maximum character count and sometimes, you just need more characters! You’ll typically run into this situation with free-form text segments like [NTE](https://www.stedi.com/edi/x12-008010/segment/NTE) and [MSG](https://www.stedi.com/edi/x12-008010/segment/MSG). In that case, you can repeat the segment to fit more data. ``` MSG*Service Terms: The Service Terms below govern your use of the Services. Capitalized terms used in these Service Terms but not defined below are either defined i) in the Stedi Customer Agreement, or ii) in other agreements with us that govern your use of the Servic~ MSG*es (collectively, the “Agreement”). 1. Universal Service Terms (Applicable to all Services) …~ ``` # Segment requirements in X12 EDI When a segment is used in a transaction set, the X12 standard specifies two types of segment requirements: `Mandatory` and `Optional`. * **Mandatory**: Segments marked as mandatory (`M`) must be present in the EDI transaction. * **Optional**: Segments marked as optional (`O`) may be present in the EDI transaction. For each transaction set, the X12 standard defines a base specification, which denotes the requirements of each segment. All segments marked as `M` (mandatory) in the base specification must be present in the EDI file sent between two trading partners. On the other hand, all segments marked as `O` (optional) in the base specification can either be optional or mandatory, depending on the implementation guide that you and your trading partner agree to. The requirement of a segment is always defined in the context of the transaction set and the position it is used in. For example, a [REF](https://www.stedi.com/edi/x12-008010/segment/REF) segment might have different requirement parameters if it is used in an [850 Purchase Order](https://www.stedi.com/edi/x12-008010/850) vs. a [270 Eligibility, Coverage, or Benefit inquiry](https://www.stedi.com/edi/x12-008010/270). Furthermore, the same segment might be used multiple times in different places in the same transaction set. For example, a [DTM Date/Time Reference](https://www.stedi.com/edi/x12-008010/segment/DTM) segment could be optional in the `Heading` but mandatory in the `Detail`. As with all things in X12 EDI, trading partners will create a specification to suit their business needs. For example, your trading partners may decide that some segments — even optional as per the standard — must be present in the data (i.e., are mandatory). On the other hand, according to the X12 standard, you cannot mark segments that are mandatory in the base X12 specification as optional in your guide. In practice, some businesses break the X12 standard and you’ll have to conform to their specification nonetheless. Most X12 implementation guides used in the industry were built using a tool called SpecBuilder, which creates a standard PDF format. We will use SpecBuilder PDFs and their terminology to explain segment requirements below, but your trading partner might send these requirements in different formats (e.g. CSV, Word, custom PDF). In these implementation guides, the segment requirements given by X12 are found in the requirement column (`Req` for short). The `Req` column will show which segments are mandatory (`M`) or optional (`O`). Trading partners that deviate from the base specification will often indicate which fields are optional or mandatory in a column called `Usage` or `Attributes`, and they typically use a different syntax, such as `Must use` (mandatory) and `Used` (optional). Image of segment requirements Additionally, the segment requirements are also usually found on the segment detail page near the description or header. In these areas, the requirements are also indicated as either mandatory or optional. For trading partner specific requirements, look for the `User Option` or `Usage` label and the `Must use` or `Used` syntax. Image of segment requirements in segment detail ## X12 types ### Mandatory Mandatory segments are marked with an `M` or `Mandatory` in most implementation guides. If a segment is defined as mandatory in a transaction set, then you cannot send X12 data without it. In most cases, transactions that are missing mandatory segments will either be stopped by the sender, or rejected by the recipient. For example, the [BIG (Beginning Segment for Invoice)](https://www.stedi.com/edi/x12-008010/segment/BIG) segment used in all X12 [810 Invoices](https://www.stedi.com/edi/x12-008010/810) is mandatory. It contains vital invoice information, such as the invoice number and date. You cannot send an invoice without these values. Image of mandatory BIG segment in 810 Image of mandatory BIG segment ### Optional Optional segments are marked with an `O` or `Optional` in most implementation guides. If a segment is marked as optional, it can be omitted in the data and the transaction would still be valid. Often, PDF specifications will explain when to use optional segments in a notes section. For example, the [CUR (Currency)](https://www.stedi.com/edi/x12-008010/segment/CUR) segment used in X12 810 Invoices is optional. Trading partners might agree that the default currency is US Dollars and use `CUR` only when the invoice currency is different from US Dollars. Image of optional CUR segment in 810 Image of optional CUR segment If you want to see the segment requirements for a specific transaction set, see [EDI Reference](https://www.stedi.com/edi/x12/transaction-set). # What is a segment in X12 EDI? Segments in X12 EDI contain a group of logically related [elements](https://www.stedi.com/edi/essentials/x12/elements) that are combined to communicate specific information between two trading partners. Each X12 transaction consists of segments sent in a pre-defined sequence, where each segment is separated from one another by segment terminators (e.g., `~`, `\n`, etc.). For example, here is a snippet of an [850 Purchase Order](https://www.stedi.com/edi/x12-008010/850) that contains a `BEG` and `CUR` segment. ``` BEG***00*AB*308174864**20220321~ CUR***BY*USD~ ``` The X12 standard defines a list of [thousands of segments](https://www.stedi.com/edi/x12/segment), and each segment has a unique segment ID, name, description, and a set of elements that it contains. These segment attributes are fixed; they do not change, regardless of what transaction set they are sent in. Most segments appear in many transaction sets, while others are unique to individual transaction sets. When a segment is used in a transaction set, the X12 standard provides additional attributes, such as its sequence, requirement, and repetition. These attributes are variable; they change based on which transaction set the segment is found in. ## Segment attributes ### IDs Each segment is given a unique ID that can be two to three characters in length, and may be a combination of letters, or letters and numbers. For example, the `Party Identification` segment has the ID `N1`, the `Tax Reference` segment has the ID `TAX`, and the `Date/Time` segment has the ID `G62`. Sometimes, the segment ID is referred to as the *segment name* or *tag*. Image of unique segment ID ### Names Each segment is given a name, which is a short, generic description of what the purpose of the segment is. For example, the name of the `ACK` segment is `Line Item Acknowledgement`, the name of the `AT1` segment is `Bill of Lading Line Item Number`, and the name of the `ITA` is `Allowance, Charge or Service`. While each segment is given a name, in practice, the segment ID is used for identifying the segment, not the name. Image of segment name ### Descriptions In addition to the segment name, X12 provides a longer description to explain what the segment represents and how it is used. For example, the `BEG` segment (Beginning Segment for Purchase Order) has the following description: > To indicate the beginning of the Purchase Order Transaction Set and transmit identifying numbers and dates. Image of segment description ### Elements Every segment contains one or more elements sent in a pre-defined order. Regardless of which transaction set the segment is found in, the segment always contains the same list of elements. However, depending on the element requirements of that segment and your trading partners implementation guide, some elements are considered optional. You can read more about elements and how they are used in the [Elements in X12 EDI](https://www.stedi.com/edi/essentials/x12/elements) article. ### Sequence For every transaction set, the X12 standard defines which segments can be sent and in what order. The order is defined by the sequence number (sometimes called position) that the segment has in the context of that transaction set. For example, in the [180 Return Merchandise Authorization and Notification](https://www.stedi.com/edi/x12-008010/180) transaction, the `ST` segment (Transaction Set Header) is the first segment that indicates a new transaction is being sent and so it is given the 0100 position of the transaction. The `BGN` segment is next up in the sequence, and has the `0200` position. `RDR` has `0300`, `PRF` has `0400`, and so on. The position number has no semantic meaning, it is purely to indicate where a segment goes in the context of its neighbors. Even if a segment is not used or sent, the position of the following segments do not change. Image of segment sequence Depending on the transaction set, the same segment can be used multiple times in different positions. The sequence number is useful here because it can help disambiguate which iteration of the segment a trading partner is referring to. For example, the `DTM` (Date/Time Reference) segment is found four times in the `180` transaction; once at the `0500` position, again at the `0520` position, again at the `1300` position, and finally at the `1900` position. On the other hand, the `252` Insurance Producer Administration transaction only contains one `DTM` segment at the `0040` position. While segment positions are useful for validation and debugging, in practice they are rarely used to describe a segment. For example, it’s rare to hear someone refer to the `DTM` as “the DTM at the 140 position.” Moreover, these positions are not always correctly calculated in the implementation guides so you shouldn’t rely on them. Instead, use the logical structure of the transaction set (e.g., heading, detail, summary, and/or loops) to explain the position. For example, the implementation guide of the `810` invoice below defines three `REF` segments with positions `050`, `110` and `120`. So, instead of using the positions (050, 110, or 120) you can refer to them as: * REF under the Heading * REF in the N1 loop * REF under detail Image of segment sequence ### Requirements When a segment is used in a transaction set, the X12 standard specifies two types of segment requirements: mandatory or optional. In addition to the X12 requirements, trading partners will often deviate slightly from the standard to suit their business needs. * **Mandatory**: segments marked as mandatory (`M`) must be present in the EDI transaction. * **Optional**: segments marked as optional (`O`) may be present in the EDI transaction. According to X12, trading partners can mark optional segments as mandatory, but they should not mark mandatory segments as optional. Additionally, while some implementation guides will mark the first segment of a loop as optional, technically all segments that are the first segment in the loop are required. ### Repetition While some segments might be present in more than one position in a single transaction set, repetition pertains to something else. The repetition attribute determines how many time the same segment or loop can be repeated in the same position. On implementation guides, this is usually referred to as the `Max Use` of a segment. The repetition of a segment in a transaction set can be indicated by one of the following: * `1`, which means this segment cannot be repeated. * Any number greater than one, which means this segment may be repeated up to, but no more than, the number indicated. * `>1`, which means that this segment can be repeated an infinite number of times Image of segment repetition # Split inbound EDI files with fragments This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. Once you [configure fragments](/edi-platform/fragments/index) for an inbound transaction setting, Stedi splits the translated transaction payload into chunks based on the selected segment. ## Processing events Stedi emits two types of events for inbound transactions with fragments enabled: `transaction.processed.v2` and `fragment.processed.v2`. For example, if you enable fragments on the `LIN` loop in an 846 Inventory Inquiry/Advice, Stedi will fragment a translated 846 file and emit the following events: * One [`transaction.processed.v2` event](/edi-platform/operate/event-types#transaction-processed) for each unique transaction set that was included in the original file. * One or more [`fragment.processed.v2` events](/edi-platform/operate/event-types#transaction-processed). Each fragment contains several iterations of the `LIN` loop (inventory items). ## Ingest fragments You have two options for ingesting fragments from processed inbound transactions into your downstream system. ### Fragment processed events Configure a [webhook](/edi-platform/configure/webhooks/configure-webhooks) for fragment processed events. As Stedi emits these events, use the [Get Fragment](/api-reference/edi-platform/core/get-transaction-fragment-detail) endpoint to retrieve each processed fragment from Stedi. ### Transaction processed events Configure a [webhook](/edi-platform/configure/webhooks/configure-webhooks) for transaction processed events only. After you receive a transaction processed event, use the API to retrieve associated fragments in batches according to your system's requirements. The event payload includes a `fragments` object with general information about the fragments that Stedi created. ```json Translated inventory file with fragments { "event": { "version": "0", "id": "85634bf9-8359-4a9b-b8f3-66616d896f51", "detail-type": "transaction.processed.v2", "source": "stedi.core", "account": "012345678910", "time": "2023-11-13T15:47:09Z", "region": "us-east-1", "resources": [ "https://core.us.stedi.com/2023-08-01/transactions/1b1d2424-72ba-4157-bcfa-3e1620430a3f" ], "detail": { "transactionId": "1b1d2424-72ba-4157-bcfa-3e1620430a3f", "direction": "INBOUND", "mode": "production", "fileExecutionId": "bb141a6f-79f8-9c88-9b91-37609ddd90f9", "processedAt": "2023-11-13T15:47:09.231Z", "fragments": { "batchSize": 800, "fragmentCount": 1, "keyName": "item_identification_LIN_loop" }, "artifacts": [ { "artifactType": "application/edi-x12", "usage": "input", "url": "https://core.us.stedi.com/2023-08-01/transactions/1b1d2424-72ba-4157-bcfa-3e1620430a3f/input", "sizeBytes": 665, "model": "transaction" }, { "artifactType": "application/json", "usage": "output", "url": "https://core.us.stedi.com/2023-08-01/transactions/1b1d2424-72ba-4157-bcfa-3e1620430a3f/output", "sizeBytes": 825, "model": "transaction" } ], "partnership": { "partnershipId": "senderid_acme", "partnershipType": "x12", "sender": { "profileId": "senderid" }, "receiver": { "profileId": "acme" } }, "x12": { "transactionSetting": { "guideId": "01H9JMMG4839VQG9QQVSZ6X29G", "transactionSettingId": "01HF4N77F5YWA2RXEDMMF5FF6J" }, "metadata": { "interchange": { "acknowledgmentRequestedCode": "0", "controlNumber": 76 }, "functionalGroup": { "controlNumber": 76, "release": "004010", "date": "2022-09-24", "time": "20:01", "functionalIdentifierCode": "IB" }, "transaction": { "controlNumber": "319101", "transactionSetIdentifier": "846" }, "receiver": { "applicationCode": "ACME", "isa": { "qualifier": "ZZ", "id": "ACME" } }, "sender": { "applicationCode": "SENDERID", "isa": { "qualifier": "ZZ", "id": "SENDERID" } } } }, "connectionId": "01H1CH2ZES1Z8AW94A3RQSRWRW" // optional } } } ``` ## Retrieve inbound transaction with fragments Stedi does not store the complete transaction for inbound files with fragments enabled. When you use Stedi's [Get Transaction](/api-reference/edi-platform/core/get-transactions) endpoint to retrieve inbound transactions with fragments, Stedi always returns the fragment wrapper (the transaction minus fragments). You cannot retrieve the complete transaction with fragments included - you must use the [Get Fragment](/api-reference/edi-platform/core/get-transaction-fragment-detail) endpoint to retrieve the fragments separately. # Fragments: Split transactions into smaller chunks This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. Large files are often the result of transaction sets containing many repeated loops or segments. For example, a healthcare provider may send an [837 Health Care Claim](https://www.stedi.com/app/guides/view/hipaa/health-care-claim-professional-x222a2/01GRYB6EJ999Y6MZ53ZBAHYBHE) containing many individual claims, or a brand may send an [846 Inventory Inquiry/Advice](https://www.stedi.com/edi/x12/transaction-set/846) file containing millions of SKUs. The translation ratio of an EDI file to JSON typically approaches 1:10, so a translated JSON artifact will be multiple times the size of the original EDI file. To avoid overwhelming downstream systems, you can use fragments to split translated inbound transactions from Stedi into smaller, more manageable chunks. You can also use fragments when generating large outbound EDI files. You send transaction data to Stedi in chunks over time, and Stedi stiches the chunks together to generate a complete EDI file for your trading partner. ## Configure fragments You need to configure your Stedi guide to use fragments and then create an inbound or outbound transaction setting using that guide. ### Stedi guide You can enable fragments for one repeated EDI segment in each transaction set. To enable fragments within a Stedi guide: 1. Go to the [Guides](https://www.stedi.com/app/guides) page and edit the guide you want to update. 2. Click the node (segment) in the guide that you want to use to split the file. The node must be a looping data structure, such as an HL loop containing inventory items. 3. Toggle **Set as fragment** to `ON`. 4. Publish the changes to your guide. ### Transaction setting Once you have enabled fragments on the Stedi guide, create a [transaction setting](/edi-platform/configure/trading-partners/transaction-settings#create-transaction-settings) with the guide. * **Inbound transaction settings**: You must explicitly toggle **Enable fragments** to `ON`. You can use the default batch size (800 segments) or set a custom batch size (up to 50,000 segments). * **Outbound transaction settings**: No additional configuration is required. You can now use fragments to split large [inbound transactions](/edi-platform/fragments/inbound-fragments) or generate large [outbound transactions](/edi-platform/fragments/outbound-fragments). # Generate outbound EDI files with fragments This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. Once you [configure fragments](/edi-platform/fragments/index) for a transaction type, you can use Stedi's APIs to generate EDI files from fragments. For example, if you enable fragments on the `INS` loop in an 834 Health Care Benefit Enrollment and Maintenance, you can send batches of `INS` loops to Stedi's [Stage Fragment API](/api-reference/edi-platform/core/post-fragments), and Stedi will securely store them until you're ready to send the complete file. Once you stage all the fragments, you call the [Create Outbound Transaction API](/api-reference/edi-platform/post-transactions) to combine the fragments together into a single EDI file and deliver it to your trading partner. ## Find the Guide JSON Schema Unless you're using [mappings](/edi-platform/mappings), you must send fragments in [Guide JSON](/edi-platform/operate/transform-json/guide-json), a JSON format that matches the JSON Schema of the guide associated with the outbound transaction setting. To find the JSON Schema for a fragment: 1. Navigate to the [Trading partners page](https://www.stedi.com/app/core/partnerships). 2. Select the partnership. 3. Click the name of the guide associated with the outbound transaction setting. 4. Open the **Actions** menu and select **View schema**. 5. Find the segment that you selected to split the file. The shape for that segment is the JSON Schema you must use when sending fragments to Stedi. The following example shows the JSON Schema for the `INS` loop in an 834 Healthcare Benefit Enrollment and Maintenance transaction. ## Find the mapping ID and schema If you plan to use a mapping to transform fragments into Stedi’s Guide JSON format, you must send fragments to Stedi's API in the mapping's source JSON schema. To find the mapping ID and schema: 1. Go to the [Mappings page](https://www.stedi.com/app/mappings) and copy the **ID** field for the mapping you want to use. 2. Click the mapping's name to view its details. 3. Click **Test mapping**. The test input JSON shape is the shape you must use when sending fragment data to the Stage Fragment API. ## Stage fragments Call the [Stage Fragments API](/api-reference/edi-platform/core/post-fragments) to store a fragment on Stedi until you are ready to generate an outbound EDI file. Stedi stores fragments in groups, specified by the `fragmentGroupID` included in the path. You can call the API with the same `fragmentGroupID` as many times as needed until you have staged all of the fragments required for the transaction. ### Data format For each staging call, you can optionally specify a mapping that Stedi will use to transform the fragment from your system's JSON format into Stedi’s Guide JSON format. * If you don’t use a mapping, the fragment must match the Guide JSON format for the specified guide. * If you use a mapping, the fragment must match the mapping's source JSON schema. ### Sample request and response The following example shows a cURL request and response for staging a fragment without a mapping. The fragment contains iterations of the `PO1` loop in an 850 Purchase Order. ## Create outbound transaction Call the [Create Outbound Transaction API](/api-reference/edi-platform/post-transactions) and Stedi combines all of the fragments matching the `fragmentGroupId` into a single, compliant EDI file and delivers it to your trading partner. Once you call the Transaction API with a `fragmentGroupId`, that ID is locked, meaning that you cannot add new fragments to the group and you cannot call the API again with that ID. This feature prevents you from accidentally sending duplicate data to partners. ### Data format When calling the API with fragments, you provide a *fragment wrapper* for the transaction. The wrapper contains all of the transaction data except for the contents of the repeated loop segment where Stedi should insert the fragments. Instead, you leave an empty array in place of the loop contents - for example, `member_level_detail_INS_loop: []`. ```json "transaction": { "heading": { "transaction_set_header_ST": { "transaction_set_identifier_code_01": "834", "transaction_set_control_number_02": 12345, "implementation_convention_reference_03": "005010X220A1" }, "beginning_segment_BGN": { "transaction_set_purpose_code_01": "00", "transaction_set_reference_number_02": "12456", "transaction_set_creation_date_03": "1998-05-20", "transaction_set_creation_time_04": "12:00", "action_code_08": "2" }, "payer_N1_loop": { "payer_N1": { "entity_identifier_code_01": "IN", "identification_code_qualifier_03": "FI", "insurer_identification_code_04": "654456654" } }, "sponsor_name_N1_loop": { "sponsor_name_N1": { "entity_identifier_code_01": "P5", "identification_code_qualifier_03": "FI", "sponsor_identifier_04": "999888777" } } }, "detail": { "member_level_detail_INS_loop": [] } } ``` You can optionally provide a mapping ID to transform the fragment wrapper from your system's JSON format into Stedi’s Guide JSON format. If you don't use a mapping, the fragment wrapper must match the Guide JSON format for the specified guide. ### Sample request and response The following example shows a cURL request and response to generate an [834 Benefit Enrollment and Maintenance](https://www.stedi.com/app/guides/view/hipaa/benefit-enrollment-and-maintenance-x220a1/01GRYB6D6RAWSG8ATBD6GXM13C). Notice that the `member_level_detail_INS_loop` is an empty array - this is where Stedi will insert the fragments from the specified fragment group. ## Retrieve an outbound transaction with fragments Call the [Get Transaction](/api-reference/edi-platform/core/get-transactions) endpoint to retrieve the full transaction, including the fragment data. Note that the full transaction, including fragments, can be very large. # Integration steps Complete the following steps to configure and test your first EDI integration on Stedi. ## Configure your first trading partner Time: About 15 minutes To set up a new trading partner, you'll need to configure the following settings: * [Partnership](/edi-platform/configure/trading-partners/profiles-and-partnerships): Partnerships describe all aspects of the EDI relationship between you and your trading partner, including which transaction sets you plan to exchange and other important information for processing. * [Connections](/edi-platform/configure/trading-partners/connections): Within the partnership, define SFTP/FTP/FTPS and AS2 connections to exchange data with partners. * [Transaction settings](/edi-platform/configure/trading-partners/transaction-settings): Within the partnership, define the inbound and outbound transaction sets you plan to exchange with your trading partner. As part of this process, you'll choose which EDI specifications to use to validate the data. ## Send webhooks to your system Time: About 5 minutes Each time Stedi processes an EDI file from a trading partner, you will want to ingest the transactions into your downstream system. You can do this by configuring a [webhook](/edi-platform/configure/webhooks/index) to send [transaction.processed.v2\` events](/edi-platform/operate/event-types#transaction-processed) to your API, Cloud functions, IPaaS platforms, or ERP systems. Then, you can programmatically retrieve the processed transaction data from Stedi. You can also configure webhooks for other events, like when a processing error occurs. You can use this approach to trigger alerts in systems like Slack, PagerDuty, or Zendesk for further review. ## Process an inbound test file Time: About 2 minutes Once you have configured your first trading partner and a webhook, you can process a test file to make sure your partner configuration is working correctly. If you don't want to wait for a test file from your partner, you can also [generate a test file](/edi-platform/operate/generate-test-files). When the test file is successfully processed, you will receive a webhook for each included transaction. ## Send an outbound test file Time: About 2 minutes You can [send a test file](/edi-platform/operate/generate-test-files) to your partner from within the browser. This is also useful for understanding what data is required to call the [Generate API](/edi-platform/operate/generate-edi) programmatically from your system. You can export cURL commands to use as a starting point for your live integration. ## Configure data transformations Time: A few hours To complete your integration, [choose an approach](/edi-platform/operate/transform-json/transformation-approaches) to transform [Stedi Guide JSON format](/edi-platform/operate/transform-json/guide-json) into and out of the format your internal systems can understand. # Gather requirements Complete the following steps in preparation for onboarding your first trading partner. Please [contact us](https://www.stedi.com/contact) with any questions. ## Project planning Work with your team to determine the following details: * **Trading partner:** Select a trading partner to integrate with. If you have multiple trading partners, we recommend starting with the partner that is either easiest to work with or that has the earliest implementation deadline. * **Timeline:** Determine your ideal implemention timeline and any hard deadlines for when the integration must be production-ready. Communicate these to your customer success engineer as soon as possible. * **Team members:** Identify the team members who will be involved in the integration. We recommend at least one project or program manager to communicate with trading partners and keep the integration on track and one engineer or technical team member. * [EDI IDs](#edi-ids): You need IDs for both your business and your trading partner before you can configure your Stedi account. ## Contact your trading partner Ask your trading partner for the following information. You and your customer success engineer will use it to configure your account. ### EDI requirements Create a list of all the EDI transaction types that you plan to send or receive. For example, you may plan to send 850 Purchase Orders and receive 810 Invoices. * **Guides:** Ask your partner for the most up-to-date EDI requirements for each transaction type. Your partner may provide these as PDF, Excel, or Word documents. {' '} These requirements may already be available in the [Stedi Network](https://www.stedi.com/edi/network). If so, we'll use the documents you provide to ensure the Network guides are up-to-date. If not, we'll add the guides you need to the Network in 1-2 business days.{' '} ### EDI IDs Determine the following IDs for both you and your trading partner. You can use the IDs in existing production EDI files or ask your trading partner to provide them. * [ISA ID](https://www.stedi.com/edi/x12/segment/ISA#ISA-06): Codes included in each EDI file's ISA header (`ISA-06` or `ISA-08`) to identify your and your partner's organization. This is usually a derivative of the company name. For example, `AMAZONDS` for Amazon Dropshipping. * [ISA Qualifier](https://www.stedi.com/edi/x12/segment/ISA#ISA-05): The type of ISA ID. If you're not sure what to choose for your business, we recommend `ZZ (Mutually Defined)`. * [Application Code](https://www.stedi.com/edi/x12-008010/segment/GS#GS-02): Codes included in each EDI file's GS header (`GS-02` or `GS-03`) to identify your and your partner's organization. The Application Code for a business is typically the same as its ISA ID, but not always. If you're new to EDI, we can help you choose values for your business. ### Connection protocol Determine how you will exchange EDI files with your partner and gather configuration details. * **Stedi-hosted SFTP/FTPS (recommended):** No additional information is required for configuration. We'll provide credentials your partner can use to connect to the server. * **Remote SFTP/FTPS:** If your partner is hosting the remote server, ask them to provide the following information: * Protocol - FTP, FTPS, SFTP * Host - server URL/address * Port number * Password or key passphrase * Root directory * Directories to retrieve files from your trading partner (inbound) and to deliver files to your trading partner (outbound) * **AS2:** This connection type is complex. If your partner requires AS2, we will discuss the requirements during your onboarding call. You can also check out our [AS2 documentation](/edi-platform/configure/trading-partners/connections/as2/as2-overview) for more information. ### Sample EDI files Gather production EDI files or ask your partner for sample files that you can use to test the integration. Trading partners often send files that do not fully conform to their official EDI requirements, so it's critical to test your pipeline with real-world data before your go-live date. # EDI platform overview In addition to our [Healthcare APIs](/healthcare), Stedi offers a platform for building and managing end-to-end EDI systems in any industry. The platform encapsulates the complexity of EDI and helps you integrate with external systems, such as ERPs, iPaaS platforms, and custom applications. ## Build an EDI system on Stedi Stedi acts as an EDI translation layer. You send JSON to Stedi, and Stedi generates EDI files and delivers them to your trading partners. Your trading partners send EDI to Stedi, and Stedi automatically translates those files into JSON and sends them to your business systems. ![Inbound and Outbound file processing flow](https://mintlify.s3-us-west-1.amazonaws.com/stediinc/images/diagrams/inbound-outbound-flow.svg) There are two main aspects to building an EDI system on Stedi. ### Onboard trading partners Anyone, regardless of their technical background or EDI experience, can add a trading partner configuration to Stedi in about 15 minutes. This involves defining the transaction sets you plan to exchange with that partner and the communication methods you plan to use (e.g. SFTP/FTPS or AS2). We can help you during a free onboarding call, or you can follow our [step-by-step instructions](/edi-platform/configure/trading-partners/). ### Integrate Stedi with internal systems After you configure your trading partner, you will set up pipelines to get transaction data into and out of Stedi. A developer can do this, or our [onboarding team](https://www.stedi.com/contact) can do it for you for free. * For each inbound transaction you receive from your trading partner, you can set up webhooks that forward processed data and events from Stedi to your systems. * For each outbound transaction you want to send to your trading partner, you can make a Stedi API call to generate and deliver fully-formed EDI files. As part of this process, you will [transform transaction data](/edi-platform/operate/transform-json/transforming-data) to and from a format that your internal systems can understand. # Advanced: Build Stedi guides You can create, import, and customize guides for any of the 300+ X12 transaction sets. Most users don't need to build custom guides - we strongly recommend importing your trading partner's guides from the [Stedi Network](https://www.stedi.com/edi/network) into your account for free. However, many trading partners send EDI files that are not 100% compliant with their official guide for a transaction set. For example, they may use different codes for an element. In these cases, you can edit existing guides so that they accurately represent the EDI files you receive. {' '} **Not sure what to fix?** If you received a guide-related file execution error, [contact us](https://www.stedi.com/contact) for help updating your guide to fix the issue. ## Edit existing guides Go to your [Stedi account](https://www.stedi.com/app/guides) and find the guide you want to edit. To edit, click the **ellipses (…)** next to the guide and select **Edit**. The guide opens in the guide builder. ## Create guides You can create a custom guide from the base specification for a transaction set from any X12 release. To create a guide: 1. Go to your [Stedi account](https://www.stedi.com/app) and click **Create guide**. 2. Select an **X12 Release** and the **Transaction Set** base specfication you want to customize. 3. Enter a unique **Name** for your guide and click **Create**. The new guide opens in the guide builder. ## Lock guides When you're finished editing, you can lock a guide to prevent further updates. Locking helps prevent accidental changes or deletions to guides in production. Any user in your Stedi account can lock guides, but only an account admin can unlock guides. To lock a guide, go to the **Actions** menu and select **Lock**. No one can update, delete, or publish a locked guide. However, you can duplicate locked guides, if needed. To unlock the guide, an admin can go to the **Actions** menu and select **Unlock**. ## Segments and Loops By default, the guide builder only lists the [segments](https://www.stedi.com/edi/essentials/x12/segments) required in the base transaction set. You can add additional segments to your custom guide. To add additional segments: 1. Click either **Heading**, **Detail**, or **Summary** in the left sidebar to view a list of the possible segments for that section. 2. Click the box next to each segment to change whether it is included in the transaction set. * `R`: Required. Note: Some PDF implementation guides use a designation of `M` (for Mandatory) instead. In these cases, `R` is still the appropriate choice. * `O`: Optional. * `N`: Not used by this implementation guide. ### Hierarchical Levels An `HL` segment identifies dependencies between hierarchically related data segments. For example, there may be hierarchical relationships between components of packing information in an [856 Ship Notice](https://www.stedi.com/edi/x12/transaction-set/856). #### Example use case Consider the following hierarchical information about customer grocery orders. ``` ORD02208 ├── Package ├── Milk ``` The following EDI example shows the HL loops that define this information. ``` HL*1**O*1~ PRF*ORD02208***20220815~ HL*2*1*P*1~ TD1*CTN*1~ REF*CN*1B487311569~ HL*3*2*I*0~ LIN*D002*BN*75206331361~ SN1**1*EA~ PID*F*TRN***MILK~ ``` The first `HL` segment defines the order at the highest level of the hierarchy. It has four elements. | Element | Name | Description | | ------- | ---------------- | --------------------------------------------------------- | | `HL-01` | ID Number | Identifies this entry of the HL loop. | | `HL-02` | Parent ID Number | The ID Number of the order that this package relates to. | | `HL-03` | Level Code | Specifies the type of the entry. In this case, a package. | | `HL-04` | Child Code | Specifies whether this entry has children. `1` means yes. | Then, the document continues: * The `PRF` segment contains information about the order itself, including the order number `ORD02208`. * The `HL` segment repeats when the order becomes a package, and the package itself is described by the segments `TD1` and `REF`. * the `HL` segment repeats once more when the order contains an item, and the item itself is described by the segments `LIN`, `SN1`, and `PID`. #### Add an HL loop to your guide X12 does not enforce a specific hierarchy in your transaction set. You can add `HL` loops to your Stedi guide to define the hierarchical relationships you need for your use case. You must add `HL` loops to your guides one level at a time. For example, you would create three nested `HL` segments to capture the following hierarchy. ``` Order ├── Package ├── Item ``` To add an `HL` loop for this scenario: 1. Click the **DETAIL** heading in the left sidebar. 2. Click the box next to the HL Loop to change its status from **Not Used**. 3. Choose a code to describe the type of entry for this level of the hierarchy. In this example, you would choose `O` for order. 4. Click **Save** to add the HL segment under **DETAIL**. 5. Click the HL Loop, scroll to the list of HL segments. 6. Click the box next to **HL Loop** to add it and select a code. In this example, you'd select `P` for package. 7. Repeat this process for the final hierarchy level describing the item. #### HL Loop Variations Sometimes, an implementation guide allows for variations of a hierarchy. For example, if a ship notice only has one package, you can leave out the package information. You can convey this information to your trading partners by creating [variants](#variants) within a single Stedi guide or by creating a separate Stedi guide for each variant. ### Variants Loops and segments allow you to create variants. A variant is a specific version of a loop or a segment that is used in a particular context. To create a variant, go to the segment and click **+ Create variant** under the **Variant group** section. #### Variant sequence Some trading partners require that you send certain iterations of loops or segments before others. To address these requirements, specify the **Variant sequence**, or position number, for each variant. This approach ensures that the variants appear in a specific order when you use this guide to write EDI. Variants with lower numbers are written before higher numbers, and variants without a defined sequence are written last. You can only set the variant sequence for loops or segments with a variant defined. To set the variant sequence, click the loop or segment you want to edit and open the **Advanced** menu. #### Discriminants Variants must be uniquely identifiable from each other. To do this, you must add a discriminant that differentiates each variant. The discriminant tells Stedi when one variant should be used over the other for validating, generating, or parsing EDI documents. For example, you could specify that partners include two `N1 Name` loops in each `850` Purchase Order: one for the ship to contact and another for the bill to party. In this case you'd add the Entity Identifier Code as the discriminant for `N1 Name` loops. For the `bill to` variant, you'd use the `BT` qualifier, and for the ship to variant, you'd use the `ST` qualifier. The type of discriminant depends on whether the loop is hierarchical: * For hierarchical loops (HL loops), set a unique HL Level Code (`HL-03`) on each variant. * For non-hierarchical loops and segments, set a unique allowed value on each variant. You do not need to place the discriminant on the first element of the first segment. You can place it in any required element of the first segment. The only requirement is that the discriminant must be unique amongst all variants. ## Elements By default, the guide builder only includes the [elements](https://www.stedi.com/edi/essentials/x12/elements) for each segment that are required in the base transaction set. You can add additional elements to your custom guide. To add or remove elements from a segment: 1. Click the segment's name and scroll to find the list of possible elements. 2. Click the box next to each element to change whether it is included in the segment. Some PDF guides have elements marked as conditional (`X`). These have special rules associated with them. At this step, you should mark them as optional. ### Conditional elements Some elements come with conditions that tell you when they should be included. For example, if you specify a date in the [date/time-segment](https://www.stedi.com/edi/x12/segment/G62), you must also specify a date qualifier. Similarly, if you specify a time, you must also specify a time qualifier. You can specify either a date or a time, but you must include at least one. Every condition begins with a letter that specifies the type of condition, followed by one or more element numbers to which the condition applies. For example, `R0103` means that you must specify at least one of the elements `01` or `03`. It’s possible to specify more than two elements, so `R010304` would mean that you must specify at least one of the elements `01`, `03`, or `04`. | **Letter** | **Name** | **Condition** | | ---------- | ---------------- | ----------------------------------------------------------------------------------------- | | `C` | Condition | If the first element is present, then all the other elements must be present. | | `E` | Exclusive | Only one of the elements may be present. | | `L` | List conditional | If the first element is present, then at least one of the other elements must be present. | | `P` | Paired | If one of the elements is present, then all elements must be present. | | `R` | Required | At least one of the elements must be present. | #### Add Conditions You must specify conditions for elements on the segment level. To add conditions: 1. Click the segment name in the left sidebar. 2. Scroll to the **Conditions** section in the center column and click **+ Add condition**. Learn more about [X12 EDI relational conditions](/edi-platform/edi-essentials/x12/elements/relational-conditions-in-x12-edi) in our EDI Reference documentation. ### Data type and length Every element has a specific data type and length. Your guide automatically copies the data type and length settings from the base specification for the transaction set. Implementation guides typically use the same data type and length as the base specification, so we recommend leaving the default settings as is, unless you have a specific reason for updating them. To edit the element's data type, click the element name in the sidebar and open the **Advanced** menu in the center column. #### Maximum length of numeric elements Numeric elements in Stedi Guides have a maximum length of 15. This differs from the X12 specification, which does not enforce a maximum length for numeric data element types. The reason for this discrepancy is that most common programming languages and libraries deserialize JSON numbers to double precision floating point numbers, which have a maximum of 15 digits of precision. This maximum length ensures that numbers do not have their value changed in the process. By default, Guides has reduced the length of certain X12 data elements to improve usability. For example, X12 element `[212 Unit Price](https://www.stedi.com/edi/x12/element/212)` has a maximum length of 17. In Guides, this is reduced to 15 by default, since very few use cases legitimately require 17 digits of pricing precision. If you need additional digits of precision, you can always change a numeric field to a string, which allows you to choose an arbitrary length. When working with numbers where precision is important, we recommend deserializing to decimal types with the appropriate precision for your business case. ### Allowed values Many elements have a value based on a standardized list of codes. For example, the date/time segment has the date qualifier segment, which indicates the type of date to include. The base specifiation lists well over a hundred possible codes. The implementation guide should list which ones are valid for you. To update the list of accepted codes for an element: 1. Click the element's name in the left sidebar. 2. Scroll to the **Allowed values** section in the center column and click **+ Add code value**. 3. Add one or more codes that are appropriate for your use cases. ## Delimiters Delimiters separate the segments and elements in an EDI file. When you create a guide, you can set delimiters in the *Overview* pane in the top left. Stedi uses the guide's delimiters when [writing EDI](/edi-platform/operate/generate-edi). As a default, Stedi recommends the following choices: * Element: `*` * Segment: `~` * Repetition: `^` * Component Element: `>` Other common choices for the component element include `:`, `<`, and `\`. Choosing delimiters for reading and writing EDI depends on your and your trading partner's data requirements. Clearly communicate the character restrictions with the business groups that are sending the data. You should also agree on substitution characters when a delimiter appears in the data. For example, if your delimiter is `*` and you know incoming data contains mathematical expressions, you could agree to use `x` instead of `*` for relevant expressions (`4x2` instead of `4*2`). ### Writing EDI Stedi will parse your data incorrectly if the delimiter you choose appears elsewhere in your data. For example, if your input uses mathematical symbols, then we recommend choosing `:` or `\` instead of `>` and `<` as delimiters. Likewise, you may want to avoid `:` if your text data includes time values in `HH:MM:SS` format. We recommend considering the following guidance from the X12 documentation. The following characters usually occur in data. They should not be used as delimiters: * Upper (`A-Z`) and lowercase (`a-z`) letters * Digits (`0-9`) * Blank space (` `) * Minus sign (`-`) The following characters often appear in data. Use as delimiter characters with caution. ``` " ! & ' ( ) * + , - . / : ; ? = ``` The following characters sometimes appear in data. Use as delimiter characters with caution. ``` % @ [ ] \_ { } \ | < > ~ ^ ` ``` ### Reading EDI #### Delimiters We recommend allowing your trading partners to use any type of delimiter when sending data. They may have different data requirements and have likely already worked to ensure there are no conflicts with EDI delimiters. Stedi automatically infers the delimiters from incoming EDI files. #### X12 guidance for delimiters X12 provides the following guidance about delimiters. The following characters usually occur in data. They should not be used as delimiters: * Upper (`A-Z`) and lowercase (`a-z`) letters * Digits (`0-9`) * Blank space (` `) * Minus sign (`-`) The following characters often appear in data. Use as delimiter characters with caution. ``` " ! & ' ( ) \* + , - . / : ; ? = ``` The following characters sometimes appear in data. Use as delimiter characters with caution. ``` % @ [ ] \_ { } \ | < > ~ ^ ` ``` ## Attachments You can attach files to any Stedi guide and choose whether the attachments are public or private (only available to members of your Stedi account). For example, you may want to add private attachments that help your team debug issues in your EDI pipeline, such as the original PDF specifications or a changelog. For a public guide, you may want to attach an appendix with a supplementary code list or a diagram that helps your partners understand the messaging flow. To add attachments to a guide in your account, navigate to its **Overview** page, scroll to the **Attachments** section, and click **Attach file**. ## Sample EDI files for public guides You can include multiple EDI sample files in Stedi guides to help new trading partners understand valid usage patterns faster and reduce onboarding time. The guide builder automatically validates each sample against the guide's specifications, so you can fix any errors before you provide them to trading partners. You can also add a description to each sample that gives trading partners even more context about the intended use cases. The description appears at the top of the guide's EDI Inspector. To add samples: 1. Click **Overview** in the left sidebar and scroll to the **EDI Samples** section in the center column. Click on **+ Add Sample**. 2. In the **EDI Sample** tab, add a **Name** and paste a sample file or customize an autogenerated sample based on the guide's specifications. 3. You may add an an optional **Description** in the **Description** tab. 4. Click **Create sample**. EDI samples attached to the guide are used: 1. In the [Generate EDI test file](/edi-platform/operate/generate-edi#send-test-files-in-the-browser) flow. 2. On your [public guide's](/edi-platform/guides/public-guides) interactive web page and are included when partners download the guide as a PDF. # Import Stedi Guides Most users don't need to create custom guides from scratch. Instead, we recommend importing guides from the [Stedi Network](https://www.stedi.com/edi/network) into your Stedi account. ### Import from our Network (Recommended) To import your partner’s EDI guides: 1. Open the [Stedi Network](https://www.stedi.com/edi/network) in a new tab. 2. Locate the trading partner and guide you want to import. 3. Click the guide to go to its details page. 4. Click **Import guide into your account**. 5. (Optional) Update the guide name. For example, you may want to add the trading partner’s name, such as **Amazon - Purchase Order**. This is helpful when you have multiple trading partners with guides for the same transaction set. 6. Click **Import**. The guide is available in your Stedi account, and you can attach it to one or more transaction settings. ### Import from another Stedi account Your trading partners and collaborators can [enable import links](#enable-importing) for private guides that let you quickly add copies of those guides to your account. **Public Guide import links:** All [Public Guides](/edi-platform/guides/public-guides) have import links enabled by default, regardless of these settings. To import a guide from another Stedi account: * Enter the guide's import link into your web browser. The Import page appears. * Choose a **Name** for the guide and then click **Import**. A private copy of the guide appears in your Stedi account. ## Enable importing You can enable an import link that allows other users to add a copy of a private guide into their Stedi account. When enabled, anyone with the import link can access your account name, guide name, and guide definition. You can disable import links at any time. To enable an import link, click the **ellipses (...)** next to a guide and select **Share import link**. Toggle **Enable import link** on. # Guides overview EDI implementation guides define the format for a particular EDI transaction type. Stedi guides are a machine-readable version of the implementation guides your partners would typically provide to you as PDF, Word, or Excel files. When you attach a guide to a [transaction setting](/edi-platform/configure/trading-partners/transaction-settings), Stedi uses it to validate and translate (inbound) or generate (outbound) the EDI files you exchange with your partner. ## Stedi Network Stedi has thousands of pre-built guides available in the [Stedi Network](https://www.stedi.com/edi/network) catalog. Once you find your partner's guides, click **Import guide into your account** to add a copy to your Stedi account. Then, you can add the guide to any partnership's [transaction settings](/edi-platform/configure/trading-partners/transaction-settings#using-guides). ## View guides You can view a list of all your guides on the **Guides** tab in your [Stedi account](https://www.stedi.com/app). # Public Guides Guides are private by default. Only members of your Stedi account can use private guides. When you [make a guide public](#make-a-guide-public), your trading partners can view it as interactive web page and validate EDI documents against it instantly in their web browsers. Visit the [Stedi Network](https://www.stedi.com/edi/network) for examples. When a guide is public, anyone with the link can: * View the guide web page * Print the guide * Troubleshoot EDI files using the EDI Inspector. ## Make a guide public To make a guide public, click the **ellipses (...)** next to the guide and select **Make public**. You can revert a public guide back to private at any time. ## Share public guide URL After the guide is public, you can send its public URL to your trading partners and link to your guides from your own website. To copy a public guide's URL: * Click the public guide to open it in the guide builder. * Click **Actions**. * Click the icon next to **View public guide** to copy the guide's public URL. ## Published guide settings You can use **Published guide settings** to customize the appearance of your public guides. These settings apply to all published guides. To change your published guide settings: 1. On the guides overview page, click **Published guide settings**. 2. You can adjust the following settings: * **Logo:** If not specified, the guide displays your Stedi account name. * **Company display name:** If not specified, the guide displays your Stedi account name. * **URL slug**: If not specified, the slug is a hyphenated version of your account name. * (Optional) **Include link:** If set to `ON`, you can add a custom link to the top of each public guide. For example, you may want to link to a particular page of your company's website. * If you include a link, specify the **Link Label**, which is the button text for your custom link and the **Link url**. # What is an EDI guide? You and your trading partner must agree on the exact format for each transaction type you plan to exchange. In practice, the larger trading partner typically dictates a format that the other trading partner must follow. These requirements are defined in what the EDI industry calls an **implementation guide**, also known as a companion guide, EDI reference guide, or just a guide. An implementation guide is similar to a Schema definition, with a few peculiarities specific to EDI. You need an implementation guide for each transaction type you plan to exchange with your partner. For example, you need an implementation guide for a purchase order and a separate guide for an invoice. ## Validation Implementation guides include information like expected fields, data types and sizes, and which fields are required. You can use these details to validate incoming and outgoing EDI documents. ## Stedi guides vs. standard guides Standard EDI implementation guides are typically captured in a static format, like PDF, CSV, or even Word document files. In contrast, Stedi guides display EDI requirements as interactive web pages with built-in validation. Stedi guides are also machine-readable, so Stedi can use them to read and write EDI documents according to each partner's EDI requirements. This is why we recommend always selecting a guide for each [transaction setting](/edi-platform/configure/trading-partners/transaction-settings) in your integration. The [Stedi Network](https://www.stedi.com/edi/network) contains hundreds of Stedi guides for popular trading partners that you can import into your Stedi account and use in your integration for free. ## Base specifications All EDI implementation guides are customized versions of a base specification. There are several EDI standards that provide base specifications. The most common are X12 and EDIFACT. The [EDI Reference](https://www.stedi.com/edi) documentation contains a full list of base specifications for each standard. * [X12 transaction sets](https://www.stedi.com/edi/x12) * [EDIFACT messages](https://www.stedi.com/edi/edifact) A base specification is designed by a standard body to cover all possible use cases for a given transaction. For example, the base specification for ship notices contains fields for every type of ship notice you could ever encounter. Base specifications are far too generic for day-to-day use. Instead, you and your trading partner must agree on what that transaction set should contain and then adjust the base specification accordingly. The result is an implementation guide, which contains only a subset of [segments](https://www.stedi.com/edi/essentials/x12/segments) from the base specification. Implementation guides can have other differences from the base specification as well. For example, some segments that are optional in the base specification may be marked as mandatory in the implementation guide. Each trading partner has their own implementation guide for each type of transaction. For example, [Home Depot](https://www.stedi.com/app/guides/view/home-depot/purchase-order/01H66G46HEFTS5NSV52VK41NZ2), [Walmart](https://www.stedi.com/app/guides/view/walmart-edi/purchase-order-acknowledgment/01GNZA51CHFJJD9Y75GSSCXHHW), and [JCPenney](https://www.stedi.com/app/guides/view/jcpenney/purchase-order-acknowledgment/01GV5KNNM3GAZHCEH5ZZ84XKTQ) all have separate implementation guides for the X12 850 Purchase Order. # Mappings - Transform JSON This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. Integrating Stedi with your internal systems requires transforming Stedi [Guide JSON](/edi-platform/operate/transform-json/guide-json) to and from a format that your system can understand. The Stedi Mappings module is a powerful JSON-to-JSON transformation engine. You can build mappings using Stedi’s visual mapper and use mappings to transform data for both inbound and outbound transactions. For example, the following mapping transforms data from a translated 850 Purchase Order (Guide JSON) to the JSON Schema required for a simple Orders API endpoint. ![Mapping example](https://mintlify.s3-us-west-1.amazonaws.com/stediinc/images/mappings/mappings-example-full.png) ## When to use Mappings There are three ways you can transform Stedi transaction data (JSON) into a custom format: Stedi Mappings, writing custom code, and using an iPaaS platform. The approach you choose depends on your circumstances and preferences. Mappings may be a good fit for your business when: * Your system can natively produce and consume JSON payloads. * You plan to do one-step transformations without multi-step processing. * You want your business or operations team to manage mappings without engineering involvement. * You want a solution that's integrated with the Stedi platform. Visit our docs on [Transformation approaches](/edi-platform/operate/transform-json/transformation-approaches) for a detailed discussion of the pros and cons of each tranformation method. ### Read EDI The most common Mappings use case is transforming processed transaction data from Stedi into a custom JSON Schema for your business system. You can use [webhooks](/edi-platform/configure/webhooks/index) to automatically send transaction processed events to any API endpoint. Then, you can use the [Map Transaction Output](/api-reference/edi-platform/get-map-transaction-output) endpoint to return the mapped output of the processed inbound transaction. ### Write EDI You can also use Mappings to transform JSON from your business systems into the [Guide JSON](/edi-platform/operate/transform-json/guide-json) format required to Stedi's API. ### Ingest Stedi events You may want to transform [Stedi events](/edi-platform/operate/event-types) into a custom shape before sending them to your business system. For example, you may want to ingest `file.failed.v2` events into applications like Slack or Zapier to create internal alerts for your operations team. # Common Mapping Expressions This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. For every field in your target, you need to write an expression that specifies how to turn input fields into an output field. The following example shows how you could output a total price from a quantity and a unit price. ``` { "total": item.quantity * item.unit_price } ``` Refer to [Mapping Definition](/edi-platform/mappings/manage-mappings/mapping-definition) for more details about mapping components. This page demonstrates mapping expressions that address common use cases. Refer to the following resources for more examples. * [Mapping expression cheatsheet][cheatsheet]: A collection of more common patterns for mapping expressions * [JSONata documentation][jsonata-docs]: A description of the JSONata language ## Basic mapping expressions You start with a target field and write a mapping expression to select the corresponding source field. The simplest mapping expression points to a single source field. **Source** ```json { "telephone": "+(1)(303) 555-0100" } ``` **Target** ```json { "phone_number": "+(1)(303) 555-0100" } ``` **Expression** | Target field | Mapping expression | | -------------- | ------------------ | | `phone_number` | `telephone` | The output will contain the key `phone_number`. In this case, the mapping expression is simply the name of a field in the source. ### Nested source fields Use a path to select nested source fields **Source** ```json { "business": { "contact": { "telephone": "+(1)(303) 555-0100" } } } ``` **Target** ```json { "phone_number": "+(1)(303) 555-0100" } ``` **Expression** | Target field | Mapping expression | | -------------- | ---------------------------- | | `phone_number` | `business.contact.telephone` | A path contains the key names at every level of a field, separated by dots. It can be tedious to write out the path for every mapping expression, especially if you have a source with a deeply nested structure. In the Mappings UI, you can click on the field in the source to copy the path to your clipboard. ## Lists To map a list in the source to a list in the target, you need to take two steps. 1. Write a mapping expression to specify which list you need from the source. 2. Write a mapping expression for each field inside the list of your target. **Source** ```json { "transaction": { "order": { "products": [ { "id": "QL-5490S", "amount": 17, "price": { "unit": 840, "total": 14280 } }, { "id": "LV-69200", "amount": 91, "price": { "unit": 15, "total": 1365 } }, { "id": "RD-0392P", "amount": 1, "price": { "unit": 930, "total": 930 } } ] } } } ``` **Target** ```json { "orders": [ { "product_number": "FF08CD", "quantity": 1, "unit_price": 20 } ] } ``` **Expression** In the target, the list is called `orders`. In the mappings UI, the field is marked with the word **array**, which is another word for list. In the source, the list that contains the relevant data has the path `transaction.order.products`, so that's the mapping expression you need for `orders`. Specify a mapping expression for each field in `orders`. For example, the field `product_number` is called `id` in the source. | Target field | Mapping expression | | ---------------- | ---------------------------- | | `orders` | `transaction.order.products` | | `product_number` | `id` | | `quantity` | `amount` | | `unit_price` | `price.unit` | The mapping expressions for the fields in the list don't include `transaction.order.products`, because Mappings knows that those fields are relative to the context of the list. For that reason, the mapping expression for a list is referred to as a *list context*. ### List indexes If the list entries of your target document are expected to include a list index number, you can access it by binding a *positional variable* to the List Context. Read about *positional variable binding* in the [JSONata docs](https://docs.jsonata.org/path-operators#-positional-variable-binding). For example, imagine you have the same source document as in the previous example, but the target document contains a new `index` property: **Source** ```json { "transaction": { "order": { "products": [ { "id": "QL-5490S", "amount": 17, "price": { "unit": 840, "total": 14280 } }, { "id": "LV-69200", "amount": 91, "price": { "unit": 15, "total": 1365 } }, { "id": "RD-0392P", "amount": 1, "price": { "unit": 930, "total": 930 } } ] } } } ``` **Target** ```json { "orders": [ { "product_number": "FF08CD", "index": 1, "quantity": 1, "unit_price": 20 } ] } ``` **Expression** To get access to the list index number, you need to define a *positional variable* for your List Context first. Then, you can use it in your mapping expression for the `index` field. Positional variables in JSONata are zero-based. | Target field | Mapping expression | | ---------------- | ------------------------------------- | | `orders` | `transaction.order.products#$myIndex` | | `product_number` | `id` | | `index` | `$myIndex + 1` | | `quantity` | `amount` | | `unit_price` | `price.unit` | Once the expression gets evaluated, you can verify that the `index` property is successfully populated for every item in the Output JSON document. This approach could create output like the following example. ```json { "orders": [ { "product_number": "QL-5490S", "index": 1, "quantity": 17, "unit_price": 840 }, { "product_number": "LV-69200", "index": 2, "quantity": 91, "unit_price": 15 }, { "product_number": "RD-0392P", "index": 3, "quantity": 1, "unit_price": 930 } ] } ``` ### Lists with one value If a list contains only one value, it will show up in the output as a single value instead of as a list. Consider the following example. **Source** ```json { "products": [ { "id": "QL-5490S" } ] } ``` **Target** ```json { "product_numbers": ["FF08CD", "RX66PL"] } ``` **Expression** | Target field | Mapping expression | | ----------------- | ------------------ | | `product_numbers` | `products.id` | You'd expect the output to be a list, just like the target example, but because there's only one product, the result is a single value. ```json { "product_numbers": "QL-5490S" } ``` If you want to make sure that the result is always an array, put `[]` at the end of the mapping expression. The following example shows the new output. ```json { "product_numbers": ["QL-5490S"] } ``` ## Objects In a generic case, to map an object in the source to an object in the target, you don't need to do anything on the object level, you only need to define expressions for each field inside of your target object. **Source** ```json { "product": { "id": "QL-5490S", "amount": 17, "price": { "unit": 840, "total": 14280 } } } } ``` **Target** ```json { "order": { "product_number": "FF08CD", "quantity": 1, "unit_price": 20 } } ``` **Expression** Specify a mapping expression for each field within the `order` object. | Target field | Mapping expression | | ---------------- | -------------------- | | `order` | | | `product_number` | `product.id` | | `quantity` | `product.amount` | | `unit_price` | `product.price.unit` | There is no expression specified on the `order` level, so all of its children have to specify a path relative to the root of the source document. ## Object context Object context is an optional expression that can be provided for any field which contains a single JSON object. By providing an object context you can improve your mappings in two ways: 1. Avoid repetition of the data transformation within child field expressions. 2. Omit whole objects from the output based on a condition. ### Avoiding repetition within child field expressions Another way to solve the same mapping from the previous example, would be to provide an *object context* for the `order`, and remove the common part of the path from expressions of its child fields. | Target field | Mapping expression | | ---------------- | ------------------ | | `order` | `product` | | `product_number` | `id` | | `quantity` | `amount` | | `unit_price` | `price.unit` | Removal of the repeated path prefix was not so dramatic, but imagine you have to map a particular member of an array in the source document, to a single object in the output document. **Source** ```json { "products": [ { "id": "QL-5490S", "amount": 17, "price": { "unit": 840, "total": 14280 } }, { "id": "LV-69200", "amount": 91, "price": { "unit": 15, "total": 1365 } }, { "id": "RD-0392P", "amount": 1, "price": { "unit": 930, "total": 930 } } ] } ``` **Target** ```json { "order": { "product_number": "FF08CD", "quantity": 1, "unit_price": 20 } } ``` **Expression** In this example, we are only interested in a product with ID starting with `LV-` prefix. | Target field | Mapping expression | | ---------------- | --------------------------------------------- | | `order` | `products[$startsWith(id, "LV-")] ~> $single` | | `product_number` | `id` | | `quantity` | `amount` | | `unit_price` | `price.unit` | The mapping expressions for the fields in the list don't include the filter expression, because Mappings knows that those fields are relative to the context of the object. For that reason, the optional mapping expression for an object is referred to as an *object context*. ### Conditionally omitting objects Mappings allows to skip an object with all of its child fields from the output based on a condition. To achieve that, specify a custom object context that evaluates to an [\$omitField constant](#dollaromitfield) when your desired conditions are met. Let's consider a case, where the source document may contain an array of products of variable length, and if the count of products in the source is `0`, a certain object should not be populated in the output. **Source** ```json { "customer": "John Doe", "products": [ { "id": "QL-5490S", "amount": 17, "price": { "unit": 840, "total": 14280 } }, { "id": "LV-69200", "amount": 91, "price": { "unit": 15, "total": 1365 } }, { "id": "RD-0392P", "amount": 1, "price": { "unit": 930, "total": 930 } } ] } ``` **Target** ```json { "customer_name": "Jane Doe", "order": { "quantity": 1, "total_price": 20 } } ``` **Expression** To omit the `order` object from the output, you should provide a ternary condition as an optional object context, and return `$omitField` when zero products were found in the source. When the omitting condition is not met, you can pass down the parent context variable `$`, which in this case would evaluate to the whole source document, the same as not providing and object context at all. | Target field | Mapping expression | | --------------- | --------------------------------------- | | `customer_name` | `customer` | | `order` | `$count(products) = 0 ? $omitField : $` | | `quantity` | `$count(products)` | | `total_price` | `$sum(products.price.total)` | ## Advanced mapping expressions Mappings allows you to do more advanced things than selecting fields. Unless you're an experienced programmer, writing complex mapping expressions will take some getting used to. We'll provide some common patterns here. If you're looking for more, check out our [mapping expressions cheatsheet][cheatsheet]. Advanced mapping expressions can get quite long. Click on the green icon next to the mapping expression you're editing to open the fullscreen view. This will give you more space to work with. ### Text to number Sometimes, your source will have quotes around a number. When that happens, Mappings thinks it's dealing with text. You can convert the text to a number by using the `$number` function. **Source** ```json { "quantity": "8" } ``` **Target** ```json { "quantity": 8 } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------- | | `quantity` | `$number(quantity)` | ### Number to text If your target contains a number in quotes, then to Mappings, that's text instead of a number. You can convert the number to text by using the `$string` function. String is another word for text. **Source** ```json { "quantity": 8 } ``` **Target** ```json { "quantity": "8" } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------- | | `quantity` | `$string(quantity)` | ### Calculations You can do calculations on numbers using `*`, `/`, `+`, and `-`. **Source** ```json { "price": 500, "quantity": 8, "discount": 150 } ``` **Target** ```json { "total": 3850 } ``` **Expression** | Target field | Mapping expression | | ------------ | ----------------------------- | | `total` | `price * quantity * discount` | If the numbers in the source are surrounded by quotes, you need to convert them first using the `$number` function. **Source** ```json { "subtotal": "500", "vat": "10" } ``` **Target** ```json { "total": 510 } ``` **Expression** | Target field | Mapping expression | | ------------ | ---------------------------------- | | `total` | `$number(subtotal) * $number(vat)` | ### Sum and average You can calculate the sum and average of a list of numbers using `$sum` and `$average`. **Source** ```json { "prices": [14280, 1365, 930] } ``` **Target** ```json { "sum": 16575, "average": 5525 } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------ | | `sum` | `sum(prices)` | | `average` | `average(prices)` | Often, the numbers you're interested in are part of a more complex structure. **Source** ```json { "orders": [ { "product_id": "QL-5490S", "price": 14280 }, { "product_id": "LV-69200", "price": 1365 }, { "product_id": "RD-0392P", "price": 930 } ] } ``` **Target** ```json { "sum": 16575, "average": 5525 } ``` **Expression** | Target field | Mapping expression | | ------------ | -------------------------- | | `sum` | `$sum(orders[].price)` | | `average` | `$average(orders[].price)` | In this case, you can refer to the field you're interested in by its full path (`price`). Make sure to put `[]` after the name of the list (`orders`) to let Mappings know that you want all prices in the list. ### Putting text together When you have to two text fields and you want to put them together, you can use `&`. **Source** ```json { "first_name": "Alice", "last_name": "Mahara" } ``` **Target** ```json { "name": "Alice Mahara" } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------------------ | | `name` | `first_name & " " & last_name` | ### Taking text apart You can extract a small part out of a text by using `$substring`. You need to specify where the part is that you're interested in, so this only works for text that follows a predictable pattern. **Source** ```json { "phone_number": "(303) 555-0100" } ``` **Target** ```json { "area_code": "303" } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------------------- | | `area_code` | `substring(phone_number, 1, 3)` | The two numbers let `$substring` know where the part begins, and how many letters you want. `$substring` starts counting characters at 0, so in the example above, we start at the second characters. If the part you're interested in is at the back of the text, you can use a negative number to tell `$substring` to start counting from the last character. **Source** ```json { "phone_number": "(303) 555-0100" } ``` **Target** ```json { "local_number": "555-0100" } ``` **Expression** | Target field | Mapping expression | | -------------- | --------------------------------- | | `local_number` | `$substring(phone_number, -8. 8)` | ### Splitting text Sometimes a text contains multiple pieces of data, separated by a character. You can turn the text into a list using `$split`. **Source** ```json { "location": "Chicago, Illinois, United States" } ``` **Target** ```json { "location": ["Chicago", "Illinois", "United States"] } ``` **Expression** | Target field | Mapping expression | | ------------ | ------------------------ | | `location` | `$split(location, ", ")` | You can assign each item in the list to a field by using an *index*, which is a number between square brackets. Items in a list are numbered starting at 0. **Source** ```json { "location": "Chicago, Illinois, United States" } ``` **Target** ```json { "city": "Chicago", "state": "Illinois", "country": "United States" } ``` **Expression** | Target field | Mapping expression | | ------------ | --------------------------- | | `city` | `$split(location, ", ")[0]` | | `state` | `$split(location, ", ")[1]` | | `country` | `$split(location, ", ")[2]` | ### Lookup table If you have a field that contains a code that you want to replace with a related value, you can build a lookup table. **Source** ```json { "country_code": "USA" } ``` **Target** ```json { "country": "United States" } ``` Before you can write a mapping expression for this, you'll need to create the lookup table. 1. Clicking the edit icon next to the mapping expression. 2. Click **Lookup tables** and select **Add new**. 3. Enter values for your table. You can add values manually, or load them from CSV. Now you can use the lookup table in your mapping expressions using the function `$lookupTable`. For example, you might create a lookup table for country codes and then write the following expression. | Target field | Mapping expression | | -------------- | ------------------------------------------------------------ | | `country_code` | `$lookupTable($tables.countries, "short" country_code).long` | A lookup table isn't limited to two values per entry; a row can have as many values as you need. For example, you could create a currency lookup table with two columns: `code` for the country code and `symbol` for the currency symbol. **Source** ```json { "currency": "USD" } ``` **Target** ```json { "currency": { "name": "U.S. Dollar", "symbol": "$" } } ``` **Expression** | Target field | Mapping expression | | ------------ | --------------------------------------------------------- | | `name` | `$lookupTable($tables.currency, "code", currency).name` | | `symbol` | `$lookupTable($tables.currency, "code", currency).symbol` | ### Lookup table wildcards You can use Lookup Tables and wildcards for matching multiple possible input options at once. In your lookup table, replace the interchangeable part of the key you want to match against with the `*` symbol (or any other sequence of symbols, you will be able to select what to match against during the `$lookupTable` function call). \-> **Note:** You can replace multiple parts of your key with `*`. Any input value that matches the loosely defined wildcard-based lookup table value is now matched when the `{ "wildcard": "*" }` is passed as an optional parameter to the `$lookupTable` function. ## Mapping types The mapping type specifies how the Mappings API generates the output field when the mapping expression doesn't produce a value. A mapping expression may not produce a value when one or more of the input fields that the mapping expression depends on aren't present. You can choose between the following mapping types: * Only mapped keys * Merge with target example * Pass through Visit [Mapping Definition Overview](/edi-platform/mappings/manage-mappings/mapping-definition#mapping-types) for full details and examples of how the Mappings UI generates outputs in each case. ## Omitting output fields There are times when a field is present in the target, but you don't want it to end up in the output. You have two options. * Deselect the target field. * Use the `$omitField` constant. ### Deselecting target fields If you don't provide a mapping expression for a target field, or if a mapping expression doesn't produce a result, the field may still end up in the output. If you don't want that, you can deselect the target field. In the following example, none of the fields in the `totals` object has a mapping expression associated with it, but it still ends up in the output. **Target** ```json { "products": [ { "id": "FF08CD" } ], "totals": { "quantity": 3, "price": 8850 } } ``` | Target field | Mapping expression | | ------------ | ------------------ | | `products` | `products` | | `id` | `id` | | `quantity` | | | `price` | | **Output** ```json { "products": [ { "id": "QL-5490S" } ], "totals": {} } ``` If you don't want `totals` to show up at all, select **Target keys** and deselect the field. This doesn't apply when you set the mapping type to *Merge with target example*, because that option will always copy the values from the the target, unless you use `$omitField`. ### \$omitField Whether a target field should end up in the output is not always a simple yes-or-no question. Sometimes, it depends on the result of the mapping expression. In that case you can use `$omitField` to tell Mappings when to skip the field. This is particularly useful if the mapping type is set to *Merge with target example* and you don't want to use the default value. In the following example, the total price is included only if the amount of products is larger than 0. **Target** ```json { "totalPrice": 3000, "unitPrice": 150 } ``` **Mapping Expression** | Target field | Mapping expression | | ------------ | ------------------------------------------ | | `totalPrice` | `amount > 0 ? amount * price : $omitField` | | `unitPrice` | `price` | **Input** ```json { "price": 150, "amount": 0 } ``` **Output** ```json { "unitPrice": 150 } ``` Without `$omitField`, the output would've included the `totalPrice` with its default value of `3000`, which is clearly wrong in this case. You can use `$omitField` in any input field on the Mapping form, including [list context](#lists) and [object context](#object-context) inputs. [mappings-product]: https://stedi.com/app/mappings [edi-translate-docs]: /legacy/edi-core#translation [cheatsheet]: /mappings/jsonata/jsonata-cheatsheet [jsonata-docs]: https://docs.jsonata.org/overview # JSONata Cheatsheet This functionality is available in a Stedi module. [Contact us](https://www.stedi.com/contact) for details. All mappings expressions are based on [JSONata language](http://docs.jsonata.org/overview.html) - this page showcases its most important features useful when creating a mapping. ## 1. JSON object source document The source for each example is derived from the following JSON: ```json { "senderName": "STEDI", "customerID": "997321", "shipmentID": 3312412, "shipment type": "ASAP", "address": { "street": "1234 Main St.", "city": "Los Angeles", "state": "CA", "country name": "USA", "is-europe": false }, "orders": [ { "orderDate": "2021/03/17", "productID": "DEG32", "quantity": 3, "pricePerUnit": 5, "volume": "10" }, { "orderDate": "2021/10/12", "productID": "OIU98", "quantity": 100, "pricePerUnit": 1, "volume": "15" }, { "orderDate": "2021/01/07", "productID": "PWE47", "quantity": 45, "pricePerUnit": 500, "volume": "35" } ] } ``` ### 1.1 Retrieving data #### Root-level field