TDS relay mailbox (0.10.0)

Download OpenAPI specification:

URL: https://github.com/kovirlabs/tds-openapi License: Apache-2.0

HTTPS mailbox for TDS CSV profile files, for providers that can only call out.

The relay mailbox (SPEC.md §9.4) moves CSV profile files (SPEC.md §9.2) between a requester and a provider whose scheduler cannot accept connections: behind an agency firewall, or inside a platform such as Google Apps Script. Unlike spec/openapi.yaml, it is served by the requester (broker or coordinator tool), and the provider's agent is the client. The agent lists the request files waiting, downloads each one, acknowledges it once it is safely stored, and uploads answers and statuses files. Every call is safe to repeat: acknowledgements are idempotent and uploads are write-once by name, so no Idempotency-Key is used. The credential names one provider's mailbox; the provider is never taken from the request.

Mailbox

Relay mailbox for CSV profile files (SPEC.md §9.4).

List request files waiting

Request files the agent has not acknowledged yet, oldest first, with each file's size and SHA-256, the provider whose mailbox this is, and the poll interval the requester expects (SPEC.md §9.4). Every authorised call counts as a poll; an agent that has a file already (same name and SHA-256) acknowledges it again instead of downloading it.

Authorizations:
mailboxToken
header Parameters
X-Relay-Agent
string <= 80 characters

Optional <agent name>/<version> of the calling agent (e.g. ridesheet-tds-connector/0.1.0), shown to the requester's operators. A header of its own because some agent platforms (Google Apps Script) cannot set User-Agent. Carries no rider data.

Responses

Response Schema: application/json
provider_id
required
string non-empty

The provider whose mailbox this is, taken from the credential. The same id the provider uses in the files' provider_id column.

poll_interval_s
required
integer >= 1

Seconds the requester expects between an agent's calls. Agents SHOULD poll about this often and no more often, apart from retries; a requester MAY report an agent as silent after three intervals without a call.

requester_id
string non-empty

The requester serving the mailbox, as it appears in the files' requester_id column. Lets an agent check its answers before uploading.

upload_reports
boolean

True when GET /inbox/{file_name} reports what became of each uploaded file's rows (SPEC.md §9.4). Absent or false: the requester does not report, and that call is 404.

max_file_bytes
integer >= 1000000

Largest upload, in bytes, PUT /inbox/{file_name} accepts; larger files are refused with FILE_TOO_LARGE (413). At least 1000000 when given.

required
Array of objects (MailboxFile)

Request files not yet acknowledged, oldest first (by created_at, then name).

Response samples

Content type
application/json
Example
{
  • "provider_id": "county-dial-a-ride",
  • "poll_interval_s": 300,
  • "max_file_bytes": 10485760,
  • "files": [
    • {
      }
    ]
}

Download a request file

One request file's bytes (SPEC.md §9.4). The agent checks X-Relay-SHA256 (and the listing's sha256) against the bytes before saving the file, and acknowledges it only after it is safely stored. A file stays downloadable after its acknowledgement until the requester deletes it under its retention rules. Reading a file changes nothing.

Authorizations:
mailboxToken
path Parameters
file_name
required
string [ 1 .. 128 ] characters

A file name in the relay mailbox (SPEC.md §9.4): letters, digits, _, - and . only, as the CSV profile names files (SPEC.md §9.2). Scoped to the mailbox the credential names.

header Parameters
X-Relay-Agent
string <= 80 characters

Optional <agent name>/<version> of the calling agent (e.g. ridesheet-tds-connector/0.1.0), shown to the requester's operators. A header of its own because some agent platforms (Google Apps Script) cannot set User-Agent. Carries no rider data.

Responses

Response Headers
X-Relay-SHA256
string^[0-9a-f]{64}$
Example: "57dd4befc5ddd8a97df0ab5cff0fd86282dccf3a5e3990db4d804cff57e3b673"

SHA-256 of the response body, lowercase hex (SPEC.md §9.4). Equals the sha256 the listing gave for the file; an agent that computes another value discards the download and fetches it again on its next poll.

Response Schema: text/csv
string

Response samples

Content type
text/csv
requester_id,provider_id,trip_id,leg_id,action,revision,rider_ref_id,rider_display_name,rider_language,rider_contact_consent,rider_phone,attendants,pickup_lat,pickup_lon,pickup_name,pickup_street,pickup_city,pickup_region,pickup_postal_code,pickup_country,dropoff_lat,dropoff_lon,dropoff_name,pickup_earliest,pickup_latest,dropoff_earliest,dropoff_latest,service_requirements,notes_to_driver,funding_source,authorization_ref
throughride-demo,county-dial-a-ride,tr-20261105-0001,leg-1,REQUEST,1,r-91c2,Ana,es,true,+15175550142,1,42.2601,-83.7795,Home,210 Example St,Ann Arbor,MI,48103,US,42.2836,-83.7286,"Regional Hospital, east entrance",2026-11-05T08:00:00-05:00,2026-11-05T08:30:00-05:00,,,WHEELCHAIR_LIFT|DOOR_TO_DOOR,"Ring bell twice, ramp at side door",MEDICAID_NEMT,PA-55120
throughride-demo,county-dial-a-ride,tr-20261105-0002,leg-1,REQUEST,1,r-4be0,,,,,,42.2215,-83.687,,,,,,,42.2475,-83.7426,Senior Center,,,2026-11-05T09:30:00-05:00,2026-11-05T10:00:00-05:00,,,SECTION_5311,
throughride-demo,county-dial-a-ride,tr-20261105-0003,leg-1,REQUEST,1,r-77d1,,,,,,42.2601,-83.7795,,,,,,,42.9634,-85.6681,Out-of-area destination,2026-11-05T07:00:00-05:00,2026-11-05T07:30:00-05:00,,,,,RIDER,

Acknowledge a request file

The agent has the file safely stored; it leaves the listing (SPEC.md §9.4). Idempotent: acknowledging again returns 200 with the first acknowledgement's time. An agent that crashes between download and acknowledgement sees the file listed again and acknowledges it then. No request body and no Idempotency-Key.

Authorizations:
mailboxToken
path Parameters
file_name
required
string [ 1 .. 128 ] characters

A file name in the relay mailbox (SPEC.md §9.4): letters, digits, _, - and . only, as the CSV profile names files (SPEC.md §9.2). Scoped to the mailbox the credential names.

header Parameters
X-Relay-Agent
string <= 80 characters

Optional <agent name>/<version> of the calling agent (e.g. ridesheet-tds-connector/0.1.0), shown to the requester's operators. A header of its own because some agent platforms (Google Apps Script) cannot set User-Agent. Carries no rider data.

Responses

Response Schema: application/json
name
required
string non-empty

The acknowledged file's name.

acked_at
required
string <date-time>

When the file was first acknowledged (RFC 3339). Later acknowledgements do not change it.

Response samples

Content type
application/json
{
  • "name": "tds_requests_20261104T150000Z.csv",
  • "acked_at": "2026-11-04T15:04:10Z"
}

Upload an answers or statuses file

Store an answers or statuses file (SPEC.md §9.2) for the requester to read, write-once by name (SPEC.md §9.4). The body is the file's raw bytes. A new name is stored (201); the same bytes under a stored name are a retry (200, applied once); other bytes under a stored name are refused (409 FILE_NAME_TAKEN) and never overwrite the stored file, so new content needs a new name. Names MUST follow SPEC.md §9.2 for answers or statuses files. No Idempotency-Key: the name is the key.

Authorizations:
mailboxToken
path Parameters
file_name
required
string [ 1 .. 128 ] characters

A file name in the relay mailbox (SPEC.md §9.4): letters, digits, _, - and . only, as the CSV profile names files (SPEC.md §9.2). Scoped to the mailbox the credential names.

header Parameters
X-Relay-Agent
string <= 80 characters

Optional <agent name>/<version> of the calling agent (e.g. ridesheet-tds-connector/0.1.0), shown to the requester's operators. A header of its own because some agent platforms (Google Apps Script) cannot set User-Agent. Carries no rider data.

Request Body schema: text/csv
required
string

Responses

Response Schema: application/json
name
required
string non-empty

The stored file's name.

stored
required
boolean

True when this upload stored the file; false when the same bytes were already there.

sha256
required
string^[0-9a-f]{64}$

SHA-256 of the stored bytes, lowercase hex, so the agent can confirm what arrived.

size
integer >= 1

Length of the stored file in bytes.

received_at
string <date-time>

When the file was first stored (RFC 3339). A retry does not change it.

Response Schema: application/json
name
required
string non-empty

The stored file's name.

stored
required
boolean

True when this upload stored the file; false when the same bytes were already there.

sha256
required
string^[0-9a-f]{64}$

SHA-256 of the stored bytes, lowercase hex, so the agent can confirm what arrived.

size
integer >= 1

Length of the stored file in bytes.

received_at
string <date-time>

When the file was first stored (RFC 3339). A retry does not change it.

Request samples

Content type
text/csv
Example
requester_id,provider_id,trip_id,leg_id,action,revision,result,status,provider_trip_id,scheduled_pickup,scheduled_dropoff,reason,answered_at
throughride-demo,county-dial-a-ride,tr-20261105-0001,leg-1,REQUEST,1,ACCEPTED,CONFIRMED,CDR-31877,2026-11-05T08:10:00-05:00,2026-11-05T08:55:00-05:00,,2026-11-04T15:40:00-05:00
throughride-demo,county-dial-a-ride,tr-20261105-0002,leg-1,REQUEST,1,ACCEPTED,CONFIRMED,CDR-31878,2026-11-05T09:05:00-05:00,,,2026-11-04T15:40:00-05:00
throughride-demo,county-dial-a-ride,tr-20261105-0003,leg-1,REQUEST,1,REJECTED,REJECTED,,,,OUTSIDE_SERVICE_AREA,2026-11-04T15:40:00-05:00

Response samples

Content type
application/json
{
  • "name": "tds_answers_20261104T204000Z.csv",
  • "stored": false,
  • "sha256": "eef2ac1723c655b97791b6abcf0e37944ccafe6e0d05bb9c104e52c36701e7cf",
  • "size": 611,
  • "received_at": "2026-11-04T20:40:05Z"
}

Read what became of an uploaded file's rows

The requester's report on an answers or statuses file this agent uploaded (SPEC.md §9.4): RECEIVED until it is read, then PROCESSED with counts and an entry for every row not applied (DUPLICATE, or REJECTED with a code and, when one cell is at fault, its column), or REFUSED when the file could not be read at all. Only for requesters whose listing says upload_reports: true; others answer 404. Reports hold row numbers, column names and codes, never cell contents, and are kept at least 7 days after the file was read. Reading a report changes nothing.

Authorizations:
mailboxToken
path Parameters
file_name
required
string [ 1 .. 128 ] characters

A file name in the relay mailbox (SPEC.md §9.4): letters, digits, _, - and . only, as the CSV profile names files (SPEC.md §9.2). Scoped to the mailbox the credential names.

header Parameters
X-Relay-Agent
string <= 80 characters

Optional <agent name>/<version> of the calling agent (e.g. ridesheet-tds-connector/0.1.0), shown to the requester's operators. A header of its own because some agent platforms (Google Apps Script) cannot set User-Agent. Carries no rider data.

Responses

Response Schema: application/json
One of
name
required
string non-empty

The uploaded file's name.

sha256
required
string^[0-9a-f]{64}$

SHA-256 of the stored bytes, lowercase hex, as in the upload receipt.

received_at
required
string <date-time>

When the file was first stored (RFC 3339).

status
required
string
Enum: "RECEIVED" "PROCESSED" "REFUSED"

RECEIVED (not read yet), PROCESSED (read row by row) or REFUSED (unreadable as a whole).

Value: "REFUSED"
processed_at
required
string <date-time>

When the requester read the file (RFC 3339). Present once PROCESSED or REFUSED.

refusal
required
string
Enum: "INVALID_ENCODING" "INVALID_HEADER" "OTHER"

Why a REFUSED file could not be read: INVALID_ENCODING (not UTF-8), INVALID_HEADER (no header row, a duplicate or unnamed column, or a required column missing), OTHER. Unknown values must be treated as OTHER.

row_count
integer >= 0

Data rows read (the header and rows with no cells not counted).

applied_count
integer >= 0

Rows applied.

duplicate_count
integer >= 0

Rows that repeated a row already applied and changed nothing.

rejected_count
integer >= 0

Rows not applied; each is listed in rows with its code.

Array of objects (MailboxRowOutcome)

Every row not applied, in file order. Empty when every row was applied.

Response samples

Content type
application/json
Example
{
  • "name": "tds_answers_20261104T204000Z.csv",
  • "sha256": "eef2ac1723c655b97791b6abcf0e37944ccafe6e0d05bb9c104e52c36701e7cf",
  • "received_at": "2026-11-04T20:40:05Z",
  • "status": "PROCESSED",
  • "processed_at": "2026-11-04T20:41:00Z",
  • "row_count": 3,
  • "applied_count": 3,
  • "duplicate_count": 0,
  • "rejected_count": 0,
  • "rows": [ ]
}