Skip to content
Connected Services Framework
Part 2 — Implementation
Markdown

#4. Message API (Letterbox)

Connected Services Framework (CSF) — Part 2: Implementation — Version 2.0

#4.1 Overview

The CSF defines a REST API — the Letterbox API — for sending and receiving messages between MAPs. This API is compatible with the TOTSCo Hub letterbox interface as defined in the TOTSCo Hub API Specification v2.0.

The Letterbox API is synchronous in its HTTP interaction: when a message is sent, the API replies within the same session. However, the messaging model is asynchronous — the HTTP 202 response acknowledges receipt, not processing completion.

#4.2 API Specification

FieldValue
API NameCSF-LetterboxAPI
HTTP MethodPOST
URI Patternhttps://{fqdn}/letterbox/{version}/post
Transport SecurityHTTPS, TLS 1.3
AuthenticationOAuth 2.0 Bearer Token
Request Formatapplication/json
Request HeadersAuthorization, Accept, Content-Type, X-CSF-SIGNATURE, X-CSF-SIGNATURE-DATESTAMP

#URI Elements

ElementDescriptionFormat
fqdnFully Qualified Domain Name of the MAP's letterbox endpointRFC 1035 compliant
versionAPI version numbern.n (e.g., 1.0)

#4.3 Message Structure

Every message consists of two parts:

  1. Envelope — Delivery instructions (source, destination, routing, audit data). Defined by the JAM Specification.
  2. Message Body — The industry process content (e.g., SforB Switch Match). Defined by the relevant process specification.

The CSF is responsible only for the envelope. The message body is opaque to the transport layer unless the MAP provides a hosted solution (portal, matching service) on behalf of its CPs.

#Envelope Example

The following JSON example uses the structure from the JAM Specification. Each auditData entry is a { "name": "<String>", "value": "<String>" } pair — both fields are strings and use double-quoted keys consistently. All JSON examples in this document have been audited for that consistency.

{
  "envelope": {
    "source": {
      "type": "RCPID",
      "identity": "d8322d80-92c8-4906-a408-f1d2daf7e03d",
      "correlationID": "XYZ987"
    },
    "destination": {
      "type": "RCPID",
      "identity": "7d87c2a7-4f64-433c-8ae1-9460f19a0a13",
      "correlationID": "ABC123"
    },
    "routingID": "businessSwitchMatchRequest",
    "auditData": [
      {
        "name": "auditFieldName",
        "value": "auditFieldValue"
      }
    ]
  },
  "_messageBody": {
    "_comment": "Process-specific message content goes here"
  }
}

#Envelope Elements

ElementDescriptionTypeRequired
envelopeContainer for delivery informationObjectYes
sourceOriginator of the message and return addressObjectYes
destinationIntended recipient of the messageObjectYes
source/type, destination/typeThe directory list type (e.g., RCPID)StringYes
source/identity, destination/identityThe RCPID of the sender/recipientStringYes
source/correlationIDUnique identifier for request correlation. MUST always be provided in source.StringYes
destination/correlationIDPresent only in response messages — contains the original sender's correlationIDStringYes in Response/Failure messages
routingIDDetermines message type and routing. Must be a value supported by the recipient MAP's routing groups.StringYes
auditDataName-value pairs for reporting and auditingArrayOptional
auditData[]/nameThe audit field nameStringYes (within array)
auditData[]/valueThe audit field valueStringYes (within array)

Note: The actual message body eelement name MUST match the routingID (e.g., businessSwitchMatchRequest). The _messageBody key shown above is illustrative.

#Audit Data Conventions

Two CSF-wide uses for auditData shape how the field SHOULD be populated by senders and read by receivers:

  • Test traffic flagging. Messages originated by, or routed on behalf of, a TEST-status CP or TEST-status MAP MUST include { "name": "test", "value": "true" }. The receiving MAP MUST preserve this flag end-to-end and MUST exclude such messages from production telemetry. The full rules — including the MAP-overrides-CP behaviour and the per-message exclusion criteria — are defined in Onboarding & Testing Process §5 — Test Traffic Flagging in the JAM Envelope and §5.1 — Telemetry Exclusion.
  • Match-session sequencing for telemetry. A SforB Switch Match journey often spans several businessSwitchMatchRequest attempts as the GRCP corrects its data. Session and attempt metadata SHOULD be carried in auditData so multi-attempt journeys can be aggregated as a single customer journey when MAPs compute industry KPIs, rather than each attempt inflating the failure rate. The recommended match* / serviceMatch* / lrcp* / map* field-name prefixes and the three-layer GRCP/LRCP/MAP scheme are summarised in Onboarding & Testing Process §5, with the full proposal in REVIEW.md §6.5 — Match Session Sequencing.

#4.4 Successful Response

On successful validation and acceptance, the API returns:

HTTP 202 Accepted

"The request has been accepted for processing, but the processing has not been completed. The request might or might not be eventually acted upon and may be disallowed when processing occurs."

No JSON body is returned on a successful 202 response.

#Validation Performed Before 202

The receiving MAP validates the following:

  1. OAuth 2.0 token validity
  2. JSON message structure
  3. Envelope attribute validity
  4. Source type and RCPID validity
  5. Source RCPID account status
  6. Destination type and RCPID validity
  7. Destination RCPID account status
  8. Source MAP authorisation via _mapkey DNS verification — see §4.4.1 below.
  9. Routing ID validity
  10. DKIM signature verification (via X-CSF-SIGNATURE)

The MAP could perform these in any order, but the MAP MUST NOT respond until all checks have passed.

#4.4.1 Per-Message Source-MAP Verification (Step 8 detailed)

For every inbound message, in addition to the DKIM signature verification defined in §3.4, the receiving MAP MUST verify that the originating MAP is the one currently authorised by the source CP in DNS:

  1. The receiving MAP MUST resolve [sourceRCPID]._mapkey.[source-cp-domain] in DNS, where sourceRCPID is taken from envelope.source.identity and source-cp-domain is the signing domain from the DKIM d= tag in the X-CSF-SIGNATURE header.
  2. The receiving MAP MUST extract the originating MAP's letterbox URL — for direct CSF-MAP-to-CSF-MAP traffic this is the MAP that established the TLS connection and presented the OAuth bearer token; for HMAP-forwarded traffic, it is the first non-HMAP entry in the X_CSF_ROUTE header chain (see §4.4.2 below).
  3. If the resolved _mapkey URL does not match the originating MAP's letterbox URL (compared on host + path, case-insensitive on host, case-sensitive on path, trailing-slash-insensitive), the receiving MAP MUST reject the message with HTTP 403 and CSF error code 9301 ("DNS _mapkey does not resolve to the originating MAP"). The asynchronous delivery-failure record MUST include the resolved _mapkey value (for diagnostics).
  4. DNS resolutions performed for _domainkey (§3.4) and _mapkey (this section) MUST honour the published TTL and SHOULD be served from the MAP's local DNS server per §3.3 — MAP Responsibilities (RFC 6303).

Note on 9301 scope. Error code 9301 was previously documented as the reject for rcpidStatusRequest authorisation failures only (§7.2.3). As of CSF v2.x it covers all source-MAP authorisation failures, including this per-message verification. Existing §7.2.3 usage is unchanged and is a specialisation of this general rule.

Note on TOTSCo response policy. The 9301 code is a CSF-specific failure. When operating as a Hub MAP (HMAP), TOTSCo does not implement DKIM signing (§3.6) and does not perform this check; CSF MAPs MUST NOT include 9301 in responses sent back to TOTSCo Hub traffic (§4.6). This is consistent with how CSF 8xxx codes are excluded from TOTSCo responses.

#4.4.2 HMAP-Forwarded Traffic

When a message arrives from an HMAP (e.g. TOTSCo), the originating MAP for the purposes of §4.4.1 is the first non-HMAP entry in the X_CSF_ROUTE header chain, not the HMAP itself. HMAPs do not implement DKIM signing (§3.6) and do not appear in any CP's _mapkey record — the _mapkey check therefore does not apply to the HMAP. It applies only to the underlying CSF MAP that originated the message into the HMAP.

For HMAP-only traffic where no CSF MAP appears in the route (i.e. a message originated entirely within a hub-and-spoke network), §4.4.1 is not enforced; the integrity guarantee for such traffic rests on the HMAP's own commercial controls and existing TOTSCo authentication. The boundary between HMAP-only and CSF-originated traffic is determined by the presence or absence of CSF MAP entries in X_CSF_ROUTE.

Trust assumption for X_CSF_ROUTE. The chain is treated as trustworthy on the basis of (a) the OAuth-authenticated channel each hop uses and (b) the bilateral trust model between MAPs that have completed onboarding. Signing of X_CSF_ROUTE entries by each MAP that appends to the chain is a future enhancement and not required for this clause.

#4.5 Synchronous Error Responses

#HTTP Error Codes

HTTP CodeErrorDescription
400Bad RequestInvalid JSON, missing required fields, or validation error
401UnauthorisedAuthentication failure (invalid OAuth token or API key)
403ForbiddenValid credentials but insufficient authorisation, or PKI verification failure
404Not FoundRequested resource not found
405Method Not AllowedHTTP method not supported (e.g., GET instead of POST)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected processing error
501Not ImplementedHTTP method not supported by the server
502Bad GatewayInvalid response from upstream
503Service UnavailableTemporary maintenance
504Gateway TimeoutUpstream response timeout

#Validation Error Codes (9xxx Series)

These codes are returned in the JSON error response body alongside the appropriate HTTP status code:

StepValidationHTTP CodeError Code
1OAuth 2.0 token validation401N/A
2JSON message structure400N/A
3Envelope attribute validation400N/A
4Source type validity4009002
5Source RCPID validity4009003
6Source RCPID account status4039003
7Destination type validity4009000
8Destination RCPID validity4009001
9Destination RCPID account status4039001
10Source MAP authorisation via _mapkey DNS check (§4.4.1)4039301
11Routing ID mapping to source RCP4009010
12Routing ID validity4009012

#PKI Error Codes (8xxx Series)

Error CodeMeaningRetry?
8101PERM_FAIL — Signature verification failed permanentlyNo
8102TEMP_FAIL — Signature verification failed due to temporary issue (e.g., DNS)Yes

#Synchronous Error Codes (9xxx Series)

Error CodeMeaning
9000Unknown or invalid destination Type.
9001Unknown or invalid destination ID.
9002Unknown or invalid source Type.
9003Unknown or invalid source ID.
9301DNS _mapkey does not resolve to the originating MAP — source-MAP authorisation failed (§4.4.1). Also used for rcpidStatusRequest authorisation failures (§7.2.3). Not sent to TOTSCo Hub traffic.

#Error Response Format

For validation errors:

{
  "errorCode": "9002",
  "errorText": "Unknown or invalid source Type."
}

For HTTP-level errors:

{
  "code": "400",
  "message": "Bad Request",
  "description": "Schema validation failed in the Request: [Path '/directory'] Object has missing required properties ([\"listID\"])"
}

The original documentation uses two different error response formats — one with errorCode/errorText for validation errors (9xxx,8xxx) and another with code/message/description for HTTP errors. Implementers should support both formats.

#4.6 Asynchronous Error Handling — Message Delivery Failures

When a MAP is unable to deliver a message to its intended recipient, it creates a failure notification message back to the originator using the following format:

{
  "envelope": {
    "source": {
      "type": "RCPID",
      "identity": "MAP-X-IDENTITY"
    },
    "destination": {
      "type": "RCPID",
      "identity": "ORIGINAL-SOURCE-RCPID",
      "correlationID": "ORIGINAL-CORRELATION-ID"
    },
    "routingID": "messageDeliveryFailure",
    "auditData": [
      { "name": "originalDestinationType", "value": "RCPID" },
      { "name": "originalDestination", "value": "DESTINATION-RCPID" },
      { "name": "originalRoutingID", "value": "businessSwitchMatchRequest" },
      { "name": "faultCode", "value": "9008" }
    ]
  },
  "messageDeliveryFailure": {
    "code": "9008",
    "text": "Unable to deliver the message to the destination, timed out.",
    "severity": "failure"
  }
}

#Delivery Failure Fields

FieldDescriptionType
messageDeliveryFailureContainer for delivery failure detailsObject
codeNumeric fault code for remedial actionInteger
textHuman-readable description of the faultString
severityNature of the notification: information, warning, or failureString

Note: The source does not contain a correlationID because delivery failure notifications cannot be replied to. The originator's correlation ID is returned in the destination field.

#Delivery Failure Codes (9xxx Series)

CodeDescriptionSeverity
9005Unable to deliver — no valid routeFailure
9006Unable to deliver — rejected, invalid message format (HTTP 400 from destination)Failure
9007Recipient rejected message (HTTP 404 from destination)Failure
9008Unable to deliver — timed out (HTTP 5xx or timeout after retries)Failure
9013Unable to deliver — invalid API keyFailure
9014Unable to deliver — API key expiredFailure
9015Unable to deliver — digital certificate invalidFailure
9016Unable to deliver — digital certificate expiredFailure

The CSF-specific 8xxx series is complete with 8101 (PERM_FAIL) and 8102 (TEMP_FAIL) — no further CSF 8xxx delivery failure codes are required (agreed by the TAG). When responding to TOTSCo, CSF-specific 8xxx codes MUST NOT be included in the response, since TOTSCo does not recognise them and only the industry-standard 9xxx series applies on that interface.

Error CodeMeaningRetry?
8101PERM_FAIL — Signature verification failed permanentlyNo
8102TEMP_FAIL — Signature verification failed due to temporary issue (e.g., DNS)Yes

#4.7 Message Delivery Policy

This section ratifies the CSF's message delivery policy for MAP-to-MAP exchanges. It also marks the boundary at which TOTSCo's hub-side principles (the OTA2 "GPLB Switching for Business Message Delivery Principles") bind on the TOTSCo side — see §4.7.4.

The policy was formalised by the TAG following the comparative analysis against the OTA2 principles document (see the CSF-vs-GPLB-MDP Analysis Report). The architectural framing in §4.7.1 below explains why CSF retains its own P2P delivery policy rather than adopting the GPLB hub schedules wholesale.

#4.7.1 Architectural framing — synchronous P2P vs hub boundary

The CSF is a peer-to-peer synchronous transport. Two MAPs exchange JAM messages directly over TLS 1.3 / OAuth 2.0 / DKIM-signed HTTP. The sending MAP knows the result of its delivery attempt in the same HTTP exchange:

  • HTTP 202 confirms the receiving MAP has accepted the message for downstream processing.
  • HTTP 4xx plus a synchronous 9xxx industry error code confirms the receiving MAP has rejected it for a documented reason.
  • A network / connection / response timeout signals that the receiving MAP is unreachable.

This is materially different from a centralised hub model — where the hub sits between sender and destination and absorbs the delivery asynchrony, queueing, retrying on a per-protocol schedule, ageing stale queue items, and emitting asynchronous failure notifications back to the sender on a separate channel. CSF MAPs do none of that at the framework layer. The synchronous response IS the delivery indication for the transport step.

The asymmetry has one important boundary: the HMAP interface between a CSF MAP and TOTSCo. TOTSCo is a hub by its own design, so traffic crossing that boundary follows the GPLB Message Delivery Principles on TOTSCo's side. See §4.7.4 below.

#4.7.2 Required behaviours (CSF MAP-to-MAP)

When a sending MAP attempts to deliver a JAM message to a receiving MAP's letterbox, the following are required:

  • Connection timeout: 1 second. TCP / TLS handshake to the destination MUST succeed within 1 second or the attempt is treated as a failed delivery and feeds into the retry loop.
  • Response timeout: 3 seconds. Once connected, the sender waits 3 seconds for HTTP 202. If no response is received within 3 seconds, the attempt is treated as a failed delivery and feeds into the retry loop.
  • Retry with exponential backoff and jitter. See §4.7.5 for the architectural rationale. MAPs MUST NOT use linear or fixed-cadence retry schedules at the CSF P2P boundary.
  • Respect HTTP semantics. MAPs MUST honour 503 Service Unavailable and 429 Too Many Requests with the destination's Retry-After header. A Retry-After value overrides the sender's normal backoff schedule for that attempt.
  • Circuit-breaker pattern. MAPs MUST implement a circuit-breaker: after N consecutive failures to the same destination (recommended N = 5, tunable per MAP), the sender SHOULD stop active retry, fail subsequent messages fast for a recovery period, and raise an operational alert.
  • Bounded maximum retry period. MAPs MUST NOT "wait forever". The framework recommends a maximum retry window in the order of hours, not days — typically 1–4 hours for production traffic. Persistent failure beyond the window triggers the escalation in §4.7.3.
  • All delivery attempts MUST be logged. Log entries include the destination URL, timestamp, attempt number, outcome, and any synchronous error code returned. Audit retention follows §9 audit-log requirements.

#4.7.3 Operational-engagement escalation

When a destination MAP fails persistently beyond the sender's retry window, the CSF's primary recovery mechanism is operational engagement between MAP operations teams — not silent retry. The procedure:

  1. The failing MAP publishes a map/outage[] entry in its CP Registry (per §5.4 Field Reference). Every other MAP picks it up on the next directory poll and applies the appropriate downgrade to retry behaviour (see Part 2 §9.3 Outage Notification).
  2. The sender raises an internal alert when its retry window is exhausted. The alert records the destination RCPID, the duration of consecutive failure, and the last synchronous error code observed.
  3. Operations teams from both sides engage via the published map/contact[] channels (phone, email, ticketing URL — see §5.6 CP Contact Object). Contact entries include availability hours, days, and purpose tags so the sender knows which channel is appropriate at the time of the incident.
  4. The framework's standard incident response process applies — see Part 1 §10.6.5 Incident Response Coordination.

This sequence is the deliberate replacement for "wait 12 days" hub-side queue ageing. CSF MAPs do not silently retry for days; they escalate. A persistent destination failure is a P1 / P2 incident, not a routine retry condition.

#4.7.4 The HMAP boundary

When a CSF MAP exchanges traffic with TOTSCo via the dedicated HMAP interface, the boundary inherits hub behaviour by definition. TOTSCo is a centralised hub, and the GPLB Switching for Business Message Delivery Principles V0.2 (OTA2) bind TOTSCo's hub-side delivery to the destination RCP. Specifically:

  • The 1 s connection / 3 s response timeouts in §4.7.2 are aligned with the GPLB principles — no asymmetry on those two values.
  • TOTSCo applies its own hub-side retry schedules per the GPLB principles — linear 5 / 10 / 15 / 20 / 25 s for Match Requests within a 30 s window; 10 / 20 / 30 / 60 s then a 60 s fixed-cadence tail for other SforB messages within a 12-day window.
  • TOTSCo emits asynchronous failure notifications back to the sender's pre-configured failure endpoint when hub-side delivery fails. The CSF MAP receives those notifications as a standard hub client.
  • TOTSCo operates the single-flight-per-endpoint queue and queue ageing on its hub side.

The HMAP interface is locked down per §6.3.1. CSF version increments — including any future change to §4.7 itself — do NOT propagate through the dedicated TOTSCo endpoints. The asymmetric behaviour at the HMAP boundary is stable and bilateral by design, so the GPLB hub schedules do not bleed back into the wider CSF P2P transport.

For the full operating model — including the per-MAP dedicated endpoint pattern, the worked NowYoYo / Red Company bidirectional example, and the locked-down interface architectural commitment — see the standalone TOTSCo HMAP Integration Guide.

#4.7.5 Why exponential backoff (and not linear / fixed-cadence retry)

The CSF retains exponential backoff with jitter as its P2P default. The linear and fixed-cadence retry schedules in the OTA2 GPLB Message Delivery Principles (5 / 10 / 15 / 20 / 25 s for Match Requests; 10 / 20 / 30 / 60 s then a 60 s cadence for other messages) are architecturally appropriate for a single centralised hub but inappropriate for a distributed P2P network for two distinct reasons:

  1. Linear schedules synchronise retry storms. When a destination is recovering, many CSF MAPs hitting it at exactly the same intervals creates the "thundering herd" effect that exponential-with-jitter is specifically designed to prevent. Under linear retry pressure, the destination has a synchronised load spike every 5 s (Match) or every 60 s (other) until it falls back over. Under exponential-with-jitter pressure, the load is spread across the recovery window and the destination is far more likely to recover cleanly.

  2. Exponential-with-jitter is the industry-standard distributed-systems pattern. Every modern cloud SDK (AWS, Google, Microsoft, Cloudflare, etc.) uses this pattern as its default retry policy. The pattern is documented in the SRE literature and is the recommended approach for any service operating across multiple independent clients. The CSF aligns with that practice; the alignment is deliberate, not incidental.

The framework's principle is therefore: exponential backoff with jitter, bounded by a maximum retry window, with operational escalation taking over beyond that window. Specific exponential parameters (base, cap, jitter range) are MAP implementation choices; the SHAPE of the curve — geometric growth with randomisation — is required.

#What exponential backoff with jitter means in practice

  • Exponential backoff: when a request fails, wait a short period, then exponentially grow the delay between subsequent retries (e.g. 1 s, 2 s, 4 s, 8 s, 16 s, capped at some maximum). This gives the struggling destination time to recover instead of repeatedly hammering it.
  • Jitter: a random component (typically ±25 %) added to each delay, so independent clients spread their retries across the recovery window rather than aligning on identical intervals.

This is the only retry shape that scales gracefully as the CSF network grows. Linear retries do not.

#4.7.6 Summary of bindings

RuleCSF MAP-to-MAP (P2P)HMAP boundary (CSF MAP ↔ TOTSCo)
1 s connection timeoutMUSTMUST (aligned with GPLB)
3 s response timeoutMUSTMUST (aligned with GPLB)
Exponential backoff with jitterMUSTTOTSCo applies GPLB linear / fixed-cadence schedule on its hub side; CSF MAP applies exponential on its own retries to TOTSCo
Respect Retry-After on 429 / 503MUSTMUST
Circuit-breakerMUSTMUST (CSF MAP side); n/a on hub side
Maximum retry periodMUST be bounded (hours)TOTSCo applies the GPLB 30 s Match / 12-day other-message holds
Failure notification to senderSynchronous — 9xxx / 8xxx in the original responseAsynchronous from TOTSCo when hub-side delivery fails; CSF MAP consumes as a standard hub client
Operational escalation via map/contact[] / map/outage[]Primary recovery mechanism beyond the retry windowApplies on the CSF MAP side; TOTSCo follows its own incident process
Logging of every delivery attemptMUSTMUST

For test cases that exercise these behaviours, see Onboarding & Testing Process §8.7 Retry & Delivery Policy.