Skip to main content
This guide is for marketplaces, auction platforms, and other products that arrange transport on behalf of the businesses that use them. Bahn calls this kind of credential an ordering channel. One ordering channel does both of these: ordered_for is optional. Leave it out and the order behaves exactly like an order from any other customer: your own Bahn account owns it. Add it and Bahn assigns the order to the business you name. You do not need a second credential to switch between the two. You decide per request. If your company only ever arranges its own transports, you do not need an ordering channel. Use a standard credential and ignore ordered_for. Contact support@bahnexpress.com to have your account configured as an ordering channel before you start production testing.

Compare the two requests

Everything else in the request stays the same.
The order response contains "ordered_for": null.
Send the same ordered_for value in the price check and in the order that follows it. A price check for your own account and an order for another business can return different prices.

Name the represented business

Send the official business ID and the country code of the business:
The supported country codes are FI, DK, DE, and PL. Bahn ignores spaces, punctuation, and a leading country prefix when it matches the business ID, so FI12345678, 12345678, and 1234567-8 all reach the same business. The country_code must match the country on that business’s Bahn account. In production the business must already exist as a Bahn customer, and exactly one must match. A request that matches none, or more than one, is rejected with ordered_for_customer_not_found. Ask support@bahnexpress.com to confirm the setup before your first production order for a new business. The represented business does not need its own API credential or a Bahn portal account, and there is no separate consent or grant step in the API flow.

Check before showing the order flow

Call POST /v2/represented-business-checks when your platform needs to decide whether to offer Bahn transport for a business. Send the business identity directly:
A successful check returns only the eligibility result:
The check does not expose the Bahn customer ID, name, or profile data, and it does not create a customer or order. In production, handle ordered_for_customer_not_found as not eligible. When no customer matches, the sandbox still returns eligible, so it tests your integration flow rather than production customer existence. More than one matching customer is rejected in both environments.

Understand who owns what

The represented business owns the transport and the commercial order. You own the integration: the customer reference, the stored Bahn order ID, the webhook handling, and the support relationship with Bahn. An ordering channel can read and change every order that belongs to its own Bahn account, regardless of where the order was created. It can also read and change orders it created for another business. It cannot read other orders of a business it represents. If the represented business also has its own Bahn credential, it can read the order you created for it. When you rotate your credential, the replacement keeps access to every order the ordering channel created.

Store the context you need

Keep these values together in one record: The same context appears in webhook events and report rows, so one integration can serve many businesses without mixing their data.

Route webhooks

Configure one webhook endpoint for your ordering channel. Read data.ordered_for on every order event to decide which business the event belongs to. A null value means the order is your own. Bahn can also deliver the same event to an active endpoint that the represented business configured. Both deliveries carry the same event ID and order sequence, so each receiver deduplicates normally. Your own orders produce a single delivery, because there is no second business to notify.

Upload files

Upload documents with your ordering-channel credential, then attach the returned file IDs to the order. The represented business can read the attached files. Only your channel can delete its own upload through the API, and only while can_delete is true.

Test the flow

The sandbox accepts any business ID in a supported country. When none matches, the sandbox creates an isolated business for that ID, so you can build the flow before any real business exists in Bahn. Cover all four cases before you go live:
  1. One represented-business check, and confirm your product offers the order flow only after eligible.
  2. One order without ordered_for, and confirm your product treats it as your own.
  3. Two orders with different ordered_for values, and confirm your storage, webhook routing, and customer-facing views never mix them.
  4. One rejected request, so you handle the problem codes below.