Start Here: Carrier Connect API Essentials
Base URL, authentication, the request envelope, the response/error model, and the create-then-poll workflow you need before your first call — including the asynchronous and idempotency behaviour that most integrations get wrong.
Carrier Connect is AEB's multi-carrier shipping system. You use it to create, validate, update, and cancel shipments and pickups, generate carrier labels and customs documents, and handle returns and hazardous goods. Operations are RPC-style calls exposed over REST as JSON or XML.
This page is the one-page orientation. Read it before your first call — it covers the four things that aren't obvious from the individual endpoint pages: how errors are returned, how asynchronous processing works, why createShipment isn't idempotent, and the order to call things in.
Base URL and endpoints
https://rz3.aeb.de/{installation}/rest/DLCarrierBFBean/{operation}For example: https://rz3.aeb.de/prod1cai/rest/DLCarrierBFBean/createShipment.
{installation} identifies your environment (e.g. a test vs. production installation). The full machine-readable contract for every operation is the OpenAPI 3.1 spec at:
https://rz3.aeb.de/prod1cai/rest/openapi.jsonThat spec covers the whole Transport & Freight Management platform; Carrier Connect operations are tagged Shipping and live under the DLCarrierBFBean bean.
Authentication
Authenticate in the request Authorization header — credentials never go in the request body. Carrier Connect (DLCarrierBFBean) operations accept either scheme:
- HTTP Basic —
Authorization: Basic base64(user:password) - Bearer token — call
GET /logon/authTokenonce with Basic credentials (orPOST /logon/userwithuserName/password/clientName), then send the returned token asAuthorization: Bearer <token>on subsequent calls.
Always send Accept: application/json too, so error responses come back as JSON rather than an HTML error page.
The globally-declared X-XNSG_WEB_TOKEN header is the browser/web session token, not an API integration path — it is rejected on these operations.
See Setting up your environment for obtaining credentials and tokens for your installation.
TheuserNamefield in the request body is not authentication. It selects which roles the request runs under: if the user exists in user management or the connected LDAP, the request runs with that user's roles; if not, it falls back to the basicI_EVERYONErole. Actual authentication is always the header above.
Request and response format
- Send
Content-Type: application/json(orapplication/xml); setAcceptto match. - Optionally set
resultLanguageIsoCodes(ordered list of 2-letter ISO codes) to control the language of returned messages. Translations fall back to the next language in the list.
The shipment request envelope
Every createShipment call has three required top-level objects plus optional identifiers:
| Object | Purpose |
|---|---|
creationParms | Whether the shipment is created — creationMode = VALIDATION_OK (create only if validation passes) or ALWAYS. |
shipment | The shipment data itself (see below). |
processParms | What happens after creation — label preparation, label output, completion, pickup assignment. |
At minimum, shipment requires: transactionId, referenceNumber1, shippingDate, contents, shippingPt (sender address), consignee (recipient address), carrierIdentCode, serviceCode, and termsOfDeliveryCode. The full object is large and deeply nested — use the OpenAPI spec as the source of truth and the The First Shipment guide for a complete copy-paste example. Don't hand-build it from memory.
Synchronous vs. asynchronous — this determines what you get back
processParms.processMode controls the single most important behaviour:
BASIC(light path): Label preparation runs asynchronously in a background job. The response only confirms the shipment was written to the database — the labels and any label-preparation errors are not in the response. You retrieve them afterwards withsyncShipmentsorgetShipments.EXTENDED(synchronous): The response does not return until label preparation is finished, so labels and preparation errors come back in-band. It uses more resources and reduces load-balancing benefit — use it only when you need an immediate, complete response.
InBASICmode, a successfulcreateShipmentresponse does not mean the label succeeded. Always pollsyncShipments/getShipmentsto confirm the operation result.
How to read every response
Operations return HTTP 200 even for business errors. Do not rely on the HTTP status code. Instead, always inspect the body:
hasErrors—truemeans the request could generally not be performed.hasWarnings—truemeans non-fatal issues.hasOnlyRetryableErrors—truemeans the errors are transient (e.g. locked data); safe to retry.messages[]— each has amessageType(ERROR/WARNING/INFO), a machine-readablemessageIdentCode, and human-readablemessageTexts[].packageResults[]— carries its ownhasErrors/messages[]per package; check these too, not just the top level.
{
"hasErrors": true,
"hasOnlyRetryableErrors": false,
"hasWarnings": false,
"messages": [
{
"messageType": "ERROR",
"messageIdentCode": "PICKUP_NOT_FOUND_ERROR",
"messageTexts": [
{ "languageISOCode": "en", "text": "Unable to find pickup for Pickup no. …" }
]
}
]
}Branch on messageIdentCode (stable, language-independent), not on the message text.
One special case: withprocessParms.doCompletion = trueandcreationParms.creationMode = VALIDATION_OK, a response ofhasErrors = falseandhasWarnings = truemeans no shipment was created. In this combination you must treat warnings as errors.
Idempotency and retries
createShipment is not idempotent. If a shipment with the same shipment.transactionId already exists, the call returns an error — it does not return or update the existing shipment. transactionId is your unique reference to the business transaction in your system, and duplicates are rejected.
Because of this, a naive retry after a timeout (common with EXTENDED mode or network blips) will fail with a duplicate error. Handle it deliberately:
- On a lost/uncertain response, call
getShipmentsfor yourtransactionIdto check whether the shipment was in fact created. - Retry
createShipmentonly if it was not. - Treat a duplicate-exists error as "already created," not as a hard failure.
The typical workflow
validateShipment (optional) → check the shipment can be processed
│
createShipment → create; processParms drives label prep/output/completion
│
syncShipments / → in BASIC mode, poll for async label results and errors
getShipments
│
processShipment → add packages, (re)print documents, complete the shipment
│
createPickup → assign shipments to a pickup and manifest to the carrierGotchas checklist
- Check
hasErrors/hasWarningsin the body — not the HTTP status. - Also check
packageResults[].messages[], not only the top-level messages. - In
BASICmode, pollsyncShipments/getShipmentsfor labels and async errors. - Give every shipment a unique
transactionId; expect an error on duplicates. -
doCompletion = true+VALIDATION_OK+ warnings-only ⇒ nothing was created. - Branch on
messageIdentCode, not on message text.
Where to go next
- Setting up your environment — credentials, tokens, installations.
- The First Shipment — a complete, copy-paste
createShipmentcall. - Creation Parameters and Process Parameters — the
creationParms/processParmsoptions in full. - Error Handling — the complete message model and codes.
- Sync and Get calls — retrieving results, labels, and changes.
- OpenAPI spec (
/rest/openapi.json) — the authoritative schema for every field.
Updated about 4 hours ago