Give the agent a concrete brief
Describe the transport task and where it belongs in your existing system: a staff screen, service, or background job. Name the features you need: booking, order management, tracking, documents, inspections, reports, or platform ordering. Supply the application stack, relevant existing code, and deployment environment. The standard integration orders your company’s transports on your own Bahn account and omitsordered_for. Use Platform ordering when your product orders for other businesses.
For an agent that will operate the integration, define which booking, change, and
cancellation decisions it may make from customer input.
Give the agent access to credentials through your server’s secret mechanism.
Keep secrets out of prompts, browser code, and logs. Use
https://sandbox.api.bahnexpress.fi for development and tests; keep the token host,
API host, credential, and webhook signing secret in the same environment.
Adapt this brief to your application:
Load the contract and relevant guides
For booking, start with Quickstart for one complete order. Read Integration lifecycle to connect it to your system. Use /llms.txt to find pages, then fetch the pages the task needs. Each page has a Markdown version at its URL plus.md. /llms-full.txt contains the full
docs when the agent needs broader context.
The OpenAPI document defines paths, field types, enums, scopes,
preconditions, and response shapes. The guides explain transport rules and
recovery. Use both. Keep complete examples consistent with the schemas, and
check the operation’s x-agent-preconditions, x-agent-side-effects, and
x-agent-retry where provided.
Build one working workflow first
Implement server-side token acquisition, caching, and renewal. For booking, create one order from the existing transport request. Link the returned Bahn order ID to the local record and read it back. Deliver the result through the screen, service, or job named in the brief. Add signed webhook processing when the system needs to keep transport records current. For read-only tracking or report exports, connect the required reads and refresh or pagination behaviour. A working integration can be a background job or service without a new customer-facing interface. Use durable storage for the records your workflow needs. These are application responsibilities, not additional API fields:
Persist write intent before the first request. A process restart after a timeout
must recover the same write. Tie the record to one transport request and reuse it
on repeated submissions.
customer_reference can be null and is not required
to be unique; it cannot replace that record.
Store the local view your system needs and refresh it from Bahn. The order owns
order facts. Tracking, files, and inspection reports have separate resources.
Implement writes and recovery together
For each write the workflow requires:- Read the current resource when the action depends on its state.
- Check scopes, preconditions, and current
allowed_actions. - Build the request from the operation’s schema.
- Persist a new key for a new logical write when required. File deletion needs no key.
- Send the request and store its result and request ID.
- Recover from the stable problem
codewith a bounded retry policy.
If-Match.
Order updates and cancellation need the current opaque revision inside double
quotation marks in that header.
For a resource 401, get a fresh token and retry once. After revision_conflict,
read the order and decide again from its current actions. After
idempotency_conflict, inspect the original operation and request data, including
whether the first attempt is still in progress. Do not start another order
creation to recover an unknown result. Permanent validation, credential,
permission, or business-rule errors need a corrected request or setup.
Keep event processing recoverable
If the system consumes webhooks, verify the signature against raw bytes before parsing. Atomically store the verified event and its pending work, deduplicated by eventid. Return 2xx after
durable storage, including for a duplicate. Retry failed processing independently
of webhook delivery. A crash after acknowledgement must not lose the work.
Read data.resource_url for current state; use data.related_resource_urls for
related reads. Resolve them against the origin in source and check that the
result belongs to your configured API origin before sending its access token.
Use data.order_sequence only to order events for one order. Serialize or
otherwise coordinate local refreshes so a delayed read cannot overwrite a newer
result. Make processing repeatable if a worker restarts after a partial result.
Do not expect an additional order status event after an item transition or
cancellation. Do not reconstruct the order lifecycle from event fields.
Preserve the transport facts
Send RFC 3339 timestamps with an offset and an IANA zone for each requested
window. Pickup needs
available_from or one requested window. Windows for a stop
must not overlap. For private pickups or end-customer deliveries, the pickup start
must fall on the next Helsinki calendar day or later. Required contacts still
apply. Use Orders and timing for the complete rules.
Omit ordered_for for your own account. For an ordering channel, use the same
represented business in the price check and creation, check eligibility before
offering the production flow when eligibility is not already known. Continue
only after an eligible result. Retain the business context in storage and webhook
routing. Sandbox eligibility does not prove a business
exists in production.
If an agent will operate the workflow
Expose tools for customer tasks such as booking, reading a transport, or cancelling an order. Validate business input and enforce current state in application code. Keep token renewal, write persistence, retries, and webhook verification there. This makes recovery work even when the agent loses context or the conversation ends. Return the outcome, Bahn identifiers needed for follow-up, relevant current state, available actions, and an actionable problem code. Send only the context needed for the next decision. Follow the customer’s authorized workflow for booking and cancellation; API access alone does not describe the customer’s intent.Verify before calling the work complete
Select checks for the capabilities your application uses. Use Sandbox testing for transport scenarios and controlled failure tests for cases a scenario cannot trigger directly.
Deliver code, configuration names without secrets, portal setup steps, tests and
results, and any remaining work. State which checks used fixtures and which made
real sandbox requests. If credentials or an endpoint are unavailable, leave the
exact sandbox check outstanding. Use Go live for the
production handoff.