Skip to main content

RAPID Ingestion

RAPID ingestion is the Iron Horse intake path for waybill, railcar, and order context coming from the RAPID workflow. It is not just a raw import. The API server authenticates the source, stores current waybill records, preserves history when payloads change, and can create or represent BIRCH work orders from a model order when the RAPID data is safe enough to use.

What RAPID contributes

RAPID supplies operational/business context that complements physical yard signals such as AEI reads.

Typical RAPID payload data includes:

  • Waybill ID and waybill number
  • Source system
  • Equipment initial and number
  • Equipment type
  • Equipment owner
  • Origin and destination station/code
  • Route
  • Commodity and commodity code
  • Gross/tare/net weight
  • Hazmat flag
  • Shipper and consignee
  • Waybill and shipped dates
  • Estimated arrival
  • Current status, status location, and last update
  • Billing rate/currency/terms
  • Priority, load/empty, bill of lading, and payload version
  • Full raw payload for audit/replay/debugging

RAPID should be understood as the business/order signal. It says what the external workflow knows about a car, waybill, customer, route, commodity, and expected timing.

Current production endpoints

RAPID is mounted under the Iron Horse API server:

API server: https://api.ihrailsoftware.com
Route prefix: /api/rapid
Implementation: /home/ubuntu/api-server/src/rapid-routes.ts
Compiled route: /home/ubuntu/api-server/dist/rapid-routes.js
UI page: /RAPID and /public/rapid.html

Primary endpoints:

POST /api/rapid/ingest
POST /api/rapid/birch/model-order
GET /api/rapid/waybills
GET /api/rapid/waybills/:waybill_id

Do not document, paste, or commit RAPID API keys, Supabase service keys, database passwords, or raw credential URLs. The production code must load those from approved server-side environment/secret locations.

High-level flow

RAPID ingestion has two related but distinct jobs:

  1. Waybill ingest stores and versions RAPID waybill data.
  2. BIRCH model-order import creates or represents a BIRCH work order for a RAPID railcar using a known model work order.

Authentication model

Waybill ingest

POST /api/rapid/ingest requires an API key in:

x-api-key: <client key>

The server hashes the presented key with SHA-256 and looks it up in the RAPID api_clients table. The client must exist and be active.

The authenticated client identity is attached to the request as:

client_id
client_name

That client ID becomes part of the waybill record and dedupe key.

BIRCH model-order endpoint

POST /api/rapid/birch/model-order supports the normal RAPID API-client lookup and also supports a configured server-side list of pre-hashed API keys for the BIRCH order-import use case.

This keeps the BIRCH model-order import callable by trusted integrations without exposing secrets in frontend code.

Waybill ingest behavior

Endpoint:

POST /api/rapid/ingest

Expected body shape:

{
"waybills": [
{
"waybill_id": "...",
"source": "..."
}
]
}

The payload may be nested or flat. The server supports both styles. For example, equipment values can come from either:

{
"equipment": {
"initial": "ABC",
"number": "1234",
"type": "TANK"
}
}

or flat fields such as:

{
"equipment_initial": "ABC",
"equipment_number": "1234",
"equipment_type": "TANK"
}

Required fields

Each waybill must have:

waybill_id
source

Rows missing either value are skipped.

Current-record model

The ingest endpoint stores waybills in Supabase using an is_current flag.

For each incoming waybill, the server checks for an existing current record matching:

waybill_id
source
client_id
is_current = true

Then it decides:

unchanged payload → skipped
changed payload → old current row set to is_current=false, new row inserted
new payload → inserted

This makes the table both a current-state store and a change-history store.

Dedupe behavior

If the incoming raw payload is identical to the current stored raw payload, the endpoint skips insertion. That prevents repeated sends from creating noisy duplicate history rows.

If the payload changed, the old current row is retained as history and the new payload becomes current.

Stored fields

The waybill record stores normalized columns for common UI/query needs and also stores the full raw payload.

Important columns include:

client_id
source
waybill_id
waybill_number
equipment_initial
equipment_number
equipment_type
equipment_owner
origin_station
origin_code
destination_station
destination_code
route
commodity
commodity_code
weight_gross
weight_tare
weight_net
hazmat
shipper_name
consignee_name
waybill_date
shipped_date
estimated_arrival
status_current
status_last_update
status_location
billing_rate
billing_currency
billing_terms
priority
load_empty
bill_of_lading
commodity_description
payload_version
received_at
raw_payload
is_current

RAPID viewer behavior

The RAPID UI is protected by Google SSO / app permission.

Routes:

/RAPID
/public/rapid.html

Viewer API endpoints:

GET /api/rapid/waybills
GET /api/rapid/waybills/:waybill_id

The list endpoint returns the latest current waybills, ordered by newest received time, limited to 500 records.

The detail endpoint returns:

current → current waybill row
history → older rows for the same waybill_id

This lets operators see what RAPID currently says and how that payload has changed over time.

BIRCH model-order import

Endpoint:

POST /api/rapid/birch/model-order

This endpoint is for creating or representing a BIRCH work order from RAPID railcar/order data.

It uses a known BIRCH model work order as a template:

Model work order: WO_05923

The model order supplies the default work-order structure, routing matrix tasks, job lines, job parts, optional billing rows, storage information, checklist report rows, and status/workupdate pattern.

Railcar identity

The endpoint accepts railcar identity from any of these payload fields:

railcar_id
car
rfid

The value is normalized by removing non-alphanumeric characters and uppercasing it.

BIRCH has a railcar ID length constraint, so the normalized ID must be 10 characters or fewer.

Existing active work order behavior

Before creating anything, the endpoint checks BIRCH for an active work order matching:

railcar_id = normalized railcar ID
shipped_date = 1900-01-01 00:00:00

If one exists, the endpoint does not create a duplicate work order. Instead it returns the existing work order summary with:

action: represented

If RAPID provided an estimated arrival date, the existing work order can be updated with that value.

If RAPID provided equipment type context, the railcar type can also be updated.

New BIRCH order behavior

If no active BIRCH work order exists for the railcar, the endpoint creates one by cloning the model order.

The process includes:

  1. Start a BIRCH database transaction.
  2. Confirm the model work order exists.
  3. Normalize/validate the railcar ID.
  4. Translate RAPID equipment type into a BIRCH railcar type.
  5. Insert the railcar if needed by cloning model railcar defaults.
  6. Allocate the next WO_##### work order number under lock.
  7. Insert a new BIRCH workorder row from the model order.
  8. Clone model job lines.
  9. Clone model job parts.
  10. Add a workupdate indicating creation by the selected user.
  11. Clone routing matrix task assignments.
  12. Clone supported optional rows.
  13. Commit the transaction.
  14. Return a summary.

If anything fails, the transaction rolls back.

Returned action values

The BIRCH model-order endpoint returns one of the major actions:

inserted → new BIRCH work order created
represented → existing active BIRCH work order found and represented

It also returns summary fields such as:

work_order
railcar_id
estimated_arrival_date
arrival_date
reason_to_come
routing_matrix
joblines
routing_tasks
status_id
railcar_action
railcar_type_translation

Equipment-type translation

RAPID equipment type/commodity text is translated to BIRCH railcar type IDs.

Current examples:

TANK / DOT 111 / DOT 117 → TANK
COVERED HOPPER / CVD HPR → COVERED HOPPER
HOPPER / HPR → HOPPER
BOX / BOXCAR / PLUG DOOR / HI CUBE → BOXCAR
GONDOLA / GON → GONDOLA
FLAT / FLATCAR → FLAT
REFRIGERATOR / REEFER → REFRIGERATOR

If RAPID does not send equipment type, or sends an unmapped type, the current default is TANK. That default should be reviewed carefully before expanding automation to new customer/product lanes.

The response includes how the type was matched:

rapid_equipment_type
default_missing_rapid_equipment_type
default_unmapped_rapid_equipment_type

Relationship to AEI Readers

RAPID and AEI answer different questions.

RAPID = business/order/waybill context
AEI = physical reader detection
Trackage = yard inventory state
BIRCH = work-order and billing/work context

A strong operational picture comes from reconciling all of them:

  • RAPID says what car/order is expected and what the waybill context is.
  • AEI says a car physically passed a reader.
  • Trackage says whether the yard believes the car is active on property.
  • BIRCH says whether work and billing context exists.

Example high-confidence case:

RAPID sends a valid car/order
AEI sees the same car inbound
Trackage does not already show the car active
BIRCH has no active duplicate

Example exception case:

RAPID sends a car that already has an active BIRCH work order

That should represent/update the existing order, not create a duplicate.

Operational safeguards

Important safety behavior in the current system:

  • API keys are hashed before lookup.
  • Inactive API clients are rejected.
  • Duplicate unchanged waybill payloads are skipped.
  • Changed waybills preserve previous rows as history.
  • BIRCH order creation runs inside a transaction.
  • Active BIRCH railcars are represented instead of duplicated.
  • Work order numbers are allocated while the workorder table is locked for update.
  • Full raw RAPID payloads are retained for audit/debugging.

Troubleshooting checklist

When RAPID data does not appear or looks wrong:

  1. Confirm the RAPID source is sending to the correct endpoint.
  2. Confirm the request includes x-api-key.
  3. Check whether the API client is active in the RAPID client table.
  4. Confirm each waybill has waybill_id and source.
  5. Check whether the payload was skipped because it matched the existing raw payload.
  6. Inspect the current row and history rows for the waybill ID.
  7. For BIRCH order creation, verify the railcar ID normalizes to 10 characters or fewer.
  8. Check whether an active BIRCH work order already exists for the railcar.
  9. Verify the model work order still exists and has the expected template content.
  10. Review API server logs for [RAPID] messages.

Never paste RAPID API keys, Supabase service keys, database passwords, or raw credential-bearing URLs into chat, docs, commits, memory, or task logs.

Maintenance notes

  • Treat model work order changes as production-affecting.
  • Review equipment-type mappings before adding new traffic lanes.
  • Keep raw payload retention because it is the main audit/replay mechanism.
  • Prefer adding explicit mapping rules over relying on default TANK fallback.
  • When changing the ingest schema, update the viewer and documentation together.
  • When changing BIRCH model-order behavior, test inserted and represented paths.