Skip to content

Partner Capacity Exchange Protocol

Generated from PROTOCOL.md. Edit the canonical source file, not this page.

Working name: OpenFreytProtocol / PCX
Status: Pre-alpha design, not an implementation contract
Language: Protocol names and schemas use English

PCX provides the smallest interoperable contract required for mutually accepted logistics partners to discover compatible capacity and demand, tender transport work, create explicit commitments, transfer a bounded execution package and prove the operational outcome.

It is a full private exchange protocol, not a universal transport model. It deliberately avoids copying complete vendor-native orders, shipments, rides, routes, invoices, vehicles, customers or contracts. Connected systems retain their local records and link them through protocol identifiers and namespaced external references.

The normative execution-transfer behavior is defined by specification/private-exchange-profile.md.

Layer Choice
Encoding UTF-8 JSON
Payload semantics JSON Schema 2020-12
Synchronous transport HTTPS using OpenAPI 3.1
Event envelope CloudEvents 1.x
Event channel description AsyncAPI, optional
Authentication OAuth 2.0 Client Credentials; OIDC for interactive users where applicable
Error payloads RFC 9457 Problem Details
Time RFC 3339 UTC timestamps; IANA time-zone identifier when local-time interpretation matters
Geometry GeoJSON RFC 7946
Countries ISO 3166-1 alpha-2
Currency ISO 4217
Locations UN/LOCODE where available
Units UNECE Recommendation 20/21 codes
Resource IDs UUIDv7 preferred; opaque to consumers

JSON Schema is the source of truth for shared payload structures. OpenAPI is normative for HTTP paths, authorization, status codes and headers, and references the schemas rather than redefining them.

  1. Every resource belongs to exactly one owning organization.
  2. Visibility requires an active bilateral PartnerRelationship and matching scope.
  3. An offer or request is not a legal or operational commitment.
  4. A proposal is explainable and non-binding.
  5. An award or commitment requires explicit authorized acceptance according to the configured decision policy.
  6. Retried commands are idempotent.
  7. Events can be delivered more than once; consumers deduplicate by event ID.
  8. Resources carry a monotonically increasing resourceVersion.
  9. State-changing events preserve causal order per resource.
  10. Historical decisions and execution outcomes cannot be silently overwritten.
  11. Exact addresses and customer identity are not required before acceptance.
  12. The public contract does not contain Freyt-specific identifiers or implementation details.
  13. Commercial acceptance and technical handover acknowledgement are separate facts.
  14. Duplicate handover delivery cannot create duplicate destination work.
  15. Accepted decision-relevant terms cannot change without a linked revision and required renewed acceptance.
  16. Payload fields cannot override the authenticated connector’s organization binding.
  17. Connected systems retain their local records; the exchange transfers only the bounded canonical execution package.

Every resource includes:

{
"id": "0195d8d2-18c7-7b18-9b4e-06d26469c821",
"resourceVersion": 1,
"ownerOrganizationId": "org_carrier_a",
"createdAt": "2026-09-15T08:00:00Z",
"updatedAt": "2026-09-15T08:00:00Z",
"externalReferences": [
{
"system": "carrier-a-tms",
"type": "trip",
"value": "TRIP-4812"
}
]
}

External references are namespaced and never treated as globally unique without system and type.

Represents bilateral authorization between two organizations.

Minimum fields:

  • id
  • requestingOrganizationId
  • acceptingOrganizationId
  • status: pending | active | suspended | terminated
  • scopes: allowed resource/action combinations
  • visibilityPolicy
  • effectiveFrom
  • effectiveUntil, optional
  • retentionPolicyRef, optional

A relationship becomes active only after authorized acceptance. Termination stops future sharing but does not erase required audit history.

Represents available vehicle or trip capacity.

Minimum fields:

  • common envelope;
  • status: draft | published | partiallyMatched | matched | withdrawn | expired | cancelled;
  • availabilityWindow;
  • originArea;
  • destinationArea;
  • direction, optional when areas imply direction;
  • vehicleProfile;
  • availableCapacity;
  • constraints;
  • maximumDetour, optional;
  • expiresAt;
  • visibility: explicit partner IDs or a relationship-defined group.

Capacity dimensions are explicit and independently optional:

{
"availableCapacity": {
"weight": { "value": 12000, "unitCode": "KGM" },
"volume": { "value": 32, "unitCode": "MTQ" },
"loadingMetres": { "value": 7.2, "unitCode": "MTR" },
"palletSpaces": 18
}
}

A consumer must not infer an unspecified dimension.

Represents demand for transport capacity, not a complete commercial order.

Minimum fields:

  • common envelope;
  • status: draft | published | proposed | matched | withdrawn | expired | cancelled;
  • pickupArea and pickupWindow;
  • deliveryArea and deliveryWindow;
  • requiredCapacity;
  • vehicleRequirements;
  • handlingRequirements, optional;
  • goodsProfile with coarse, non-sensitive classification;
  • expiresAt;
  • visibility.

Customer identity, exact address, price and complete goods details are excluded unless policy explicitly permits disclosure.

An immutable proposal connecting one compatible offer and request. A newer proposal supersedes rather than mutates an accepted rationale.

Minimum fields:

  • capacityOfferId and observed version;
  • loadRequestId and observed version;
  • status: open | accepted | rejected | expired | superseded | withdrawn;
  • validUntil;
  • compatibility results;
  • routeCompatibility, including structured distance or detour estimates when available;
  • capacityCompatibility, including the dimensions used for comparison;
  • rationale as structured reason codes plus human-readable summary;
  • requiredDecisionPolicy;
  • createdBy: broker, participant or authorized planner.

The proposal must never disclose protected fields merely because the broker found a potential match.

An append-only decision made by an authorized organization.

Minimum fields:

  • proposalId;
  • organizationId;
  • decision: accept | reject | withdraw;
  • decidedAt;
  • decidedBy as actor reference;
  • reasonCode, optional;
  • comment, optional and access-controlled;
  • observedProposalVersion.

The decision policy defines whether both organizations must accept and which role may decide. A stale version returns a conflict; the server does not silently apply the decision to a changed proposal.

A versioned request for a selected partner to execute a bounded transport movement. It freezes the decision-relevant terms shown to the recipient and references the originating proposal where applicable.

Minimum fields:

  • issuing and intended executing organizations;
  • movement scope: fullTransport | routeLeg | collection | delivery;
  • expiry and required decision policy;
  • cargo, equipment, stop and time-window requirements allowed at the current disclosure phase;
  • commercial terms or a stable external terms reference;
  • amendment and cancellation policy;
  • source external references.

A counterproposal creates a new immutable revision. It never silently modifies terms already presented for decision.

Immutable proof that every decision required by the tender policy was accepted before expiry or valid withdrawal.

Minimum fields:

  • accepted tender revision;
  • required decisions and actors;
  • acceptance timestamps;
  • deterministic digest of the accepted decision-relevant payload;
  • relationship-policy version;
  • resulting capacity reservation or consumption.

A commitment proves agreement. It does not prove that the executing system imported the work.

A disclosure-controlled operational package containing only the stops, time windows, cargo facts, equipment constraints, references, instructions, documents and contact details required to execute the committed movement.

The source and executing systems retain their own local records. The handover links them through the commitment identifier and namespaced external references.

Records whether the executing connector imported, linked, rejected or quarantined the handover. Successful acknowledgements include the destination external reference. Duplicate delivery must resolve to the same local record and acknowledgement.

Commercial acceptance and technical handover acknowledgement are separate transitions.

Links a commitment and handover to local execution records without copying a complete connected-system object.

Minimum fields:

  • commitment and handover references;
  • participating organization references;
  • source and destination external references;
  • execution status;
  • planned and actual time range;
  • cancellation or exception reason where applicable.

Communicates shared milestones and exceptions without replacing either participant’s detailed local state. Baseline milestones are assigned | atPickup | pickedUp | inTransit | delayed | atDelivery | delivered | failed | cancelled | disputed.

Records whether and how a commitment was executed without copying the participants’ complete operational records.

Minimum fields:

  • commitment, handover and execution reference;
  • status: planned | inProgress | completed | cancelled | failed | disputed;
  • planned and actual time range;
  • participant confirmations;
  • external execution references;
  • operational deviations or exception reason, where applicable;
  • optional capacity-utilization and route observations;
  • deduplication key;
  • correction/supersession reference.

Execution outcomes are append-only. A correction points to the superseded record and includes a reason.

Prefer intent-revealing commands over arbitrary resource patching:

POST /partner-relationships
POST /partner-relationships/{id}/accept
POST /partner-relationships/{id}/suspend
POST /capacity-offers
POST /capacity-offers/{id}/publish
POST /capacity-offers/{id}/withdraw
POST /load-requests
POST /load-requests/{id}/publish
POST /load-requests/{id}/withdraw
GET /match-proposals
POST /match-proposals/{id}/decisions
POST /transport-tenders
POST /transport-tenders/{id}/issue
POST /transport-tenders/{id}/decisions
POST /transport-tenders/{id}/counterproposals
POST /transport-tenders/{id}/withdraw
POST /transport-commitments/{id}/amendments
POST /transport-commitments/{id}/cancel
POST /execution-handovers
POST /execution-handovers/{id}/acknowledgements
POST /execution-references
POST /execution-updates
POST /execution-outcomes
POST /execution-outcomes/{id}/corrections

The exact endpoint set remains to be specified in OpenAPI. Generic PATCH should be limited to non-decision draft data because it obscures lifecycle semantics and audit intent.

  • Every create or command operation accepts Idempotency-Key scoped to the authenticated organization and operation.
  • The same key and identical payload returns the original outcome.
  • The same key with a different payload returns 409 Conflict.
  • State-changing commands include If-Match or an explicit observed resourceVersion.
  • Stale writes return 409 Conflict or 412 Precondition Failed with an RFC 9457 body.
  • Idempotency records must outlive the maximum client retry window.

Example event types:

pcx.partner-relationship.activated.v1
pcx.capacity-offer.published.v1
pcx.capacity-offer.withdrawn.v1
pcx.load-request.published.v1
pcx.load-request.withdrawn.v1
pcx.match-proposal.created.v1
pcx.match-decision.recorded.v1
pcx.match-proposal.accepted.v1
pcx.transport-tender.issued.v1
pcx.transport-tender.countered.v1
pcx.transport-commitment.created.v1
pcx.transport-commitment.amended.v1
pcx.transport-commitment.cancelled.v1
pcx.execution-handover.offered.v1
pcx.execution-handover.acknowledged.v1
pcx.execution.updated.v1
pcx.execution.completed.v1
pcx.execution-outcome.recorded.v1
pcx.execution-outcome.corrected.v1

CloudEvent requirements:

  • globally unique id;
  • source identifies the broker/producer;
  • subject identifies the resource;
  • type uses the versioned event name;
  • time uses RFC 3339;
  • dataschema points to an immutable schema version;
  • extension attributes include organizationid, resourceversion, correlationid and, where applicable, causationid.

Delivery is at least once. Consumers must deduplicate and ignore an event with an older or equal applied resource version. Sensitive payload projection is audience-specific.

Authorization evaluates:

  1. token validity and broker audience;
  2. active connector or interactive user registration;
  3. active organization;
  4. resource ownership or participation;
  5. active partner relationship;
  6. granted client scope;
  7. bilateral relationship policy;
  8. resource visibility policy;
  9. field disclosure phase;
  10. actor role for decisions;
  11. lifecycle preconditions;
  12. resource version and expiry.

API scope, bilateral policy and resource visibility are independent gates. Passing one does not bypass another. Connector credentials are bound to exactly one organization and environment; payload fields cannot override that binding.

Machine connectors use OAuth 2.0 Client Credentials and should use private_key_jwt or mutual TLS in production. Interactive users use OIDC Authorization Code with PKCE. Internal connected-system session tokens are not portable exchange credentials unless an explicit federation or token-exchange profile validates their issuer, audience, organization and actor semantics.

Recommended scopes:

relationships:manage
capacity:publish
capacity:read
loads:publish
loads:read
matches:read
matches:decide
tenders:publish
tenders:read
tenders:decide
commitments:read
handovers:write
handovers:read
handovers:acknowledge
execution:update
outcomes:write
outcomes:review
connectors:manage

A 404 may be preferable to 403 when revealing resource existence would leak partner activity. Broker logs must redact exact locations, customer identity and goods details by default.

Errors use RFC 9457 and stable protocol codes:

{
"type": "https://openfreytprotocol.example/problems/stale-resource-version",
"title": "Stale resource version",
"status": 409,
"code": "STALE_RESOURCE_VERSION",
"detail": "The proposal changed after it was read.",
"correlationId": "corr_019..."
}

Initial codes should cover validation, authentication, authorization, hidden resource, inactive relationship, stale version, idempotency conflict, invalid transition, expired resource and incompatible decision policy.

  • Protocol releases use semantic versioning.
  • JSON schemas have immutable versioned identifiers.
  • Additive optional fields and new event types are minor changes.
  • Changed meaning, removed fields or stricter existing validation require a major version.
  • Consumers ignore unknown optional fields but never unknown enum values in decision-critical fields unless the schema explicitly provides an other extension mechanism.
  • During the pilot, prefer additive evolution and publish deprecation windows.
  • Every proposal and execution outcome stores the schema version used.

Extensions are namespaced:

{
"extensions": {
"com.example.carrier.temperatureClass": "chilled"
}
}

An extension cannot change core semantics, authorization or lifecycle behaviour. If multiple participants need the same extension, promote it through protocol governance after conformance examples exist.

A conformant implementation must pass tests for:

  • JSON Schema validation;
  • lifecycle transitions;
  • idempotent retries;
  • stale-write rejection;
  • bilateral visibility isolation;
  • field-level disclosure;
  • duplicate and out-of-order events;
  • proposal expiry and withdrawal;
  • explicit decision policy;
  • execution-outcome deduplication and correction history;
  • RFC 9457 error responses.

Conformance profiles:

  • Publisher: capacity offers and/or load requests;
  • Consumer: discovers and decides;
  • Broker: authorization, matching, lifecycle and events;
  • Outcome provider: submits execution status and references;
  • Full reference client: implements publisher, consumer and evidence flows.

Adapters map external formats at the edge:

External TMS/EDI/UBL/EPCIS
Adapter layer
PCX contract
Reference broker

Rules:

  • do not expose adapter-specific fields in core schemas without a cross-participant use case;
  • preserve source and destination external references for traceability;
  • bind connector processing to the authenticated organization, never to an inbound tenant field;
  • document lossy mappings;
  • quarantine invalid, ambiguous or unsafe inbound messages;
  • include adapter and supported-profile versions in diagnostics;
  • do not silently invent required values;
  • process commands and events idempotently with durable inbox, outbox and mapping state;
  • reconcile authoritative resources after missed delivery or downtime;
  • expose health, lag, dead letters and mapping failures;
  • test tenant/organization isolation independently for every adapter;
  • avoid direct writes to a connected system’s internal database unless it documents that interface as supported.

15. Items requiring validation before v0.1

Section titled “15. Items requiring validation before v0.1”
  • canonical execution handover schema and movement boundaries;
  • tender counterproposal, amendment and cancellation semantics;
  • OAuth/OIDC client authentication, claims, rotation and revocation profile;
  • organization verification and connector registration model;
  • event signing, replay resistance and reconciliation profile;
  • exact vehicle/body-type vocabulary;
  • area representation: circle, polygon, administrative region or combinations;
  • recurrence model for fixed corridors;
  • bilateral decision policy and commitment semantics;
  • retention and withdrawal rules;
  • webhook signing method;
  • legal organization identifier strategy;
  • price inclusion or complete exclusion;
  • dangerous goods and temperature-control minimum fields;
  • kilometer baseline calculation specification;
  • license, trademark and governance owner.