Operate B2B Exchange
B2B Exchange receives EDIFACT orders from a trading partner in Workspace and returns the corresponding order response. This operating contract has no administration UI. Configure it through authorized server APIs and use nucli as the tenant-bound HTTP client when needed.
The current scope is deliberately narrow:
| Area | Supported |
|---|---|
| Inbound | ORDERS |
| Outbound | ORDRSP, CONTRL, and APERAK according to the active acknowledgement policy |
| Directory messages | ORDERS, ORDRSP, and APERAK in D.96A or D.25A |
| Syntax service message | CONTRL 2.2 for syntax version 3 or CONTRL 4.1 for syntax version 4 |
| Transport | Partner API and SFTP |
| Maximum payload | 16 MiB per interchange |
| Not included | Administration UI, AS2, DESADV, INVOIC, or other message types |
Read Understand and introduce EDI/EDIFACT when you first need to separate the standard, directory, and partner profile. For a new partner onboarding, Set up an EDIFACT trading partner provides a compact acceptance sequence before you use this detailed operations contract.
Understand the processing path
Workspace tracks transport, syntax, mapping, application, and acknowledgement status separately. A successful upload therefore does not prove that the order was applied or that the response was delivered.
Prepare permissions
Grant administrators only the required actions on these permission families:
b2b_exchange_partnersb2b_exchange_identifiersb2b_exchange_connectionsb2b_exchange_commerce_bindingsb2b_exchange_profiles, includingactivateb2b_exchange_messagesfor list, read, review, retry, cancel, and payload access
The action follows the colon, for example b2b_exchange_connections:create. Verify the active tenant and scopes before making a change:
nucli --tenant <tenant> whoami
nucli --tenant <tenant> scopes
nucli --tenant <tenant> api GET /api/v1/b2b-exchange/partners --summaryPass mutation bodies to nucli api with --input <file> or --input -.
Create the configuration in a stable order
Create the partner and commerce binding as inactive and create connections and profiles as drafts. Do not run live or transport tests against these states. Activate the complete contract first, then start testing and acceptance.
| Order | Object and API path | Purpose |
|---|---|---|
| 1 | Partner at /api/v1/b2b-exchange/partners | Create the trading partner with a stable key in inactive state. |
| 2 | Identifier at /api/v1/b2b-exchange/identifiers | Bind inbound and outbound EDIFACT identifiers, schemes, qualifiers, and values to the partner. |
| 3 | Connection at /api/v1/b2b-exchange/connections | Select the transport, partner identity, storage binding, and adapter with status draft. |
| 4 | Profile at /api/v1/b2b-exchange/profiles | Select direction, message type, and application policy with status draft. |
| 5 | Revision at /api/v1/b2b-exchange/profiles/{profileID}/revisions | Version the D.96A or D.25A mapping and acknowledgement policy immutably. |
| 6 | Commerce binding at /api/v1/b2b-exchange/commerce-bindings | Bind the partner and inbound ORDERS profile to company, commercial account, sales channel, commerce profile, and optional catalog or site while inactive. |
| 7 | Check activation prerequisites | Ensure that the approved fixture evidence for each revision has already succeeded. This evidence is not live or transport acceptance. |
| 8 | Activate the partner | Set the fully bound partner to active. |
| 9 | Activate profile revisions | Make exactly one revision current for each profile through /api/v1/b2b-exchange/profiles/{profileID}/revisions/{revisionID}/activate. This activates the profile. |
| 10 | Activate connections and the commerce binding | Activate only the unambiguous transport topology below and the binding of the inbound ORDERS profile. |
| 11 | Run test and acceptance | Only now submit real interchanges over the activated transport and verify the complete processing path. |
An activated revision is immutable. Create and activate a new revision when a mapping or acknowledgement policy changes. Use inbound for ORDERS and outbound for ORDRSP. The current W2 contract supports automatic, review_on_difference, and manual as application policies.
Verify fixture evidence
Create at least one fixture evidence record for each revision at /api/v1/b2b-exchange/profiles/{profileID}/revisions/{revisionID}/fixtures/. Reference existing authorized, tenant-bound Storage objects and provide their SHA-256 hashes. The fixture endpoint neither accepts nor returns payload bytes.
- For inbound
ORDERS,inputStorageObjectIdcontains EDIFACT andexpectedStorageObjectIdcontains the expected canonical JSON order. - For outbound
ORDRSP,inputStorageObjectIdcontains the canonical JSON response andexpectedStorageObjectIdcontains the expected EDIFACT document. - For
expectedOutcome: "valid", provide the expected object and its hash. LeaveexpectedErrorCodeempty. - For
expectedOutcome: "rejected", do not provide an expected object. Use onlyERR_B2B_EXCHANGE_FIXTURE_SYNTAXorERR_B2B_EXCHANGE_FIXTURE_MAPPINGasexpectedErrorCode.
New evidence has verificationStatus: "pending". Start deterministic verification with POST .../fixtures/{fixtureID}/verify. The result is terminal:
succeededwithoutobservedErrorCodeconfirms a valid fixture case.succeededwith anobservedErrorCodeequal to the expected code confirms an expected rejection case.failedpermanently records the stable error code actually observed andverifiedAt. Delete the evidence and create a corrected record; you cannot verify the same evidence again.
Activation remains blocked when evidence is absent, has not succeeded, or its expected and observed results differ. After activation, you cannot change or delete the revision or its fixture evidence. Fixture verification proves only the mapping contract; run transport and live acceptance separately afterwards.
Verify unambiguous cardinality before activation
Each active partner must have exactly this active topology:
| Contract | Required active binding |
|---|---|
| Inbound profile | Exactly one inbound profile for ORDERS with exactly one current activated revision. |
| Outbound profile | Exactly one outbound profile for ORDRSP with exactly one current activated revision. |
| Commerce | The active commerce binding references the inbound ORDERS profile, not the outbound profile. |
| Partner API | A partner may have multiple active connections with transport api and adapterKey api.v1. Each concrete connection ID binds its own inbox and outbound mailbox. |
| SFTP inbound | Each (Tenant, PartnerIdentityID, InboundStoreID) tuple permits exactly one active connection with sftp.inbound.v1. Multiple active connections with different tuples may coexist. |
| SFTP outbound | Each partner permits exactly one active connection with sftp.outbound.v1. |
A second active profile binding remains invalid. Multiple API connections and multiple SFTP inbound connections with different tuples are valid. The transport contract becomes ambiguous only with a duplicate active SFTP inbound tuple or more than one active SFTP outbound connection for the same partner.
Configure a Partner API connection
A Partner API connection uses these fixed values:
| Field | Value or binding |
|---|---|
transport | api |
adapterKey | api.v1 |
configuration | {} |
partnerIdentityId | Identity that owns the partner API key |
inboundStoreId | Tenant-bound store for inbound interchanges |
A partner may have multiple active API connections. Every request addresses a concrete connection ID; that exact connection binds both its inbox and its outbound mailbox.
The API connection does not accept credential, signing, or encryption secret IDs. Issue a fixed-tenant API key for the bound partner identity with only the required partner scopes. See Integrate the B2B Exchange Partner API for the integration contract.
Configure SFTP inbound
SFTP inbound uses the existing storage-bound SFTP listener. The connection resolves a successful upload through its identity and store:
| Field | Value or binding |
|---|---|
transport | sftp |
adapterKey | sftp.inbound.v1 |
configuration | {} |
partnerIdentityId | Identity used by the SFTP account |
inboundStoreId | Dedicated tenant-bound inbound store |
Activate exactly one SFTP inbound connection for each (Tenant, PartnerIdentityID, InboundStoreID) tuple. Multiple active inbound connections with different tuples are permitted. Prepare the storage account completely:
- Create a tenant-bound store and enable its
sftp.enabledsetting. - Grant the identity bound by
partnerIdentityIdanEditorACL on theStorageStoreresource for that exact store. - Issue an active fixed-tenant API key for the same identity. Both its requested scopes and its effective role scopes must contain
storage_object:create. - Use the same store as
inboundStoreIdand activate exactly one SFTP inbound connection for this identity/store binding.
The SFTP listener uses these canonical credentials:
| SSH field | Canonical value |
|---|---|
| Username | UUID of the store bound by inboundStoreId |
| Password | <api-key-id>:<api-key-secret> of the fixed-tenant API key owned by the same identity |
Other identity, tenant, store, or scope combinations do not resolve to a B2B connection. Other SSH login methods are outside this inbound contract. The username/password rule above is the canonical SFTP login contract for B2B Exchange.
Secure SFTP outbound
SFTP outbound uses transport: "sftp" and adapterKey: "sftp.outbound.v1". Keep only public connection metadata in configuration:
{
"host": "sftp.partner.example",
"port": 22,
"remoteDirectory": "/outbound/orders",
"hostKeySHA256": "SHA256:<verified-fingerprint>",
"connectTimeoutSeconds": 10,
"operationTimeoutSeconds": 45
}The following constraints apply:
portis fixed at22.hostKeySHA256is mandatory. Verify the SHA-256 fingerprint through a separate trusted channel.connectTimeoutSecondsmust not exceed30, andoperationTimeoutSecondsmust not exceed120.remoteDirectorymust be an absolute normalized path without traversal segments.- The destination server must provide the SFTP extension
posix-rename@openssh.com. Delivery fails when it is unavailable. - The adapter writes an exclusive temporary file, publishes it only through
posix-rename@openssh.com, and then verifies the final size and SHA-256 hash.
credentialSecretId must reference a closed JSON object in the tenant-bound secret store. Only these two forms are accepted:
type | Required fields | Optional | Must be absent |
|---|---|---|---|
password | type, username, password | none | privateKey, privateKeyPassphrase |
private_key | type, username, privateKey | privateKeyPassphrase | password |
Unknown fields or data appended after the JSON object cause an error. The complete JSON must not exceed 256 KiB. username is required, contains 1 to 128 UTF-8 bytes, and must contain no leading or trailing spaces, null bytes, or line breaks. For type password, the field with the same name is required, non-empty, and limited to 4096 UTF-8 bytes. For type private_key, privateKey must contain non-empty SSH credential material. Never place the username, a password, SSH credential material, or a passphrase in configuration, logs, tickets, or nucli command lines.
Private destinations are blocked by default. Only an operator with global configuration permission can allow selected private CIDR ranges through the locked b2b_exchange.sftp.outbound.allowed_private_cidrs setting. A tenant or connection cannot broaden this allowlist. Special-purpose destinations and mixed public/private DNS answers stay blocked, and the adapter pins the validated destination address for the connection.
Monitor and operate messages
Use the messages API for the operational lifecycle:
nucli --tenant <tenant> api GET '/api/v1/b2b-exchange/messages?limit=50' --summary
nucli --tenant <tenant> api GET /api/v1/b2b-exchange/messages/<interchange-id> --summaryInspect every status axis independently:
| Status axis | Question |
|---|---|
| Transport | Was the interchange accepted, transmitted, or confirmed? |
| Syntax | Is the EDIFACT envelope syntactically valid? |
| Mapping | Could Workspace map the message to its canonical contract? |
| Application | Was the order applied, rejected, or held for review? |
| Acknowledgement | Were the required CONTRL or APERAK messages generated and delivered? |
Use operations deliberately:
POST /api/v1/b2b-exchange/messages/{interchangeID}/retryschedules a new controlled attempt for a failed process.POST /api/v1/b2b-exchange/messages/{interchangeID}/cancelstops a process that can still be cancelled.POST /api/v1/b2b-exchange/messages/{interchangeID}/reviewapproves or rejects a message that requires business review. Send itsmessageId, useapprovewithout a reason code, orrejectwith a stable reason code.GET /api/v1/b2b-exchange/messages/{interchangeID}/payloadrequires the separate payload-read scope and creates audit records.
Do not retry blindly. Inspect the stable error code, status axes, profile revision, partner binding, and destination connection first. A retry preserves the business identity of the process; it does not replace corrected configuration.
Diagnose failures safely
The API returns stable ERR_B2B_EXCHANGE_* codes and deliberately excludes raw SQL, storage, network, and cryptographic errors. Treat this reduction as a security contract.
| Observation | Check |
|---|---|
ERR_B2B_EXCHANGE_INVALID_REQUEST | Check the JSON contract, UUIDs, adapter combination, profile revision, and status. |
ERR_B2B_EXCHANGE_PAYLOAD_TOO_LARGE | Limit the payload to 16 MiB. |
ERR_B2B_EXCHANGE_CONFLICT | Check idempotency, current status, or an already active revision. |
ERR_B2B_EXCHANGE_NOT_FOUND | Check the active tenant, permission, and tenant-bound references without probing foreign IDs. |
ERR_B2B_EXCHANGE_UNAVAILABLE or ERR_B2B_EXCHANGE_INTERNAL | Record correlation and time; inspect redacted server-side operations logs. |
Never copy a raw server error into a partner response. Share only the stable code, your own correlation, and the next safe action.
Accept the operation
The contract is ready for operation when:
- partner, identifier, exactly assigned connections, commerce binding, and the active
ORDERSandORDRSPprofile revisions belong to the correct tenant, - one test interchange for each active directory and syntax configuration passes through the expected states only after the complete activation,
- duplicates create neither a second commerce order nor a second business
ORDRSP, CONTRLandAPERAKfollow the active acknowledgement policy,- the Partner API verifies payload size, hash, and completion or SFTP confirms the atomically published file, and
- unauthorized requests disclose no foreign partner, connection, or payload information.
Developers can continue with Work with EDIFACT as a developer for mapping, fixture, and test conventions or Integrate the B2B Exchange Partner API for the complete Partner API contract.