# JUMiNGO API 1.1.0 > With the JUMiNGO shipping API you import your shipments into your JUMiNGO account from any source, fetch the shipping rates available for them, buy the shipping labels and retrieve tracking data, labels and documents for every shipment you purchased. > [!WARNING] > **Test request sends real calls.** The *Test request* panel next to every operation calls `https://api.jumingo.com` with the token you enter, so a `POST` creates a real shipment or order in your account. There is no sandbox yet; use read operations such as `GET /v1/shipments` to explore, and keep your token out of shared screens. The token is stored only in your browser. ## About With the JUMiNGO shipping API you import your shipments into your JUMiNGO account from any source, fetch the shipping rates available for them, buy the shipping labels and retrieve tracking data, labels and documents for every shipment you purchased. Its main purpose is to connect your account to e-commerce systems and marketplaces. ## General The API is organised around REST: resource-oriented URLs, JSON request and response bodies, standard HTTP verbs and HTTP status codes. All requests must be made over HTTPS; plain HTTP calls fail. Best-practice usage of the API and the business logic behind it are described in the guides on [developers.jumingo.com](https://developers.jumingo.com/), starting with the [quickstart](https://developers.jumingo.com/#description/quickstart). ## Base URL All paths in this reference are relative to `https://api.jumingo.com`, so the shipments collection is `https://api.jumingo.com/v1/shipments`. ## Authentication Every request needs a credential of your JUMiNGO account: a **personal access token** (recommended) or the **legacy API key**. A request without either is answered with `401` and `{"message": "No API token provided"}`. ### Personal access token (recommended) Enable the customer API under [Connections](https://www.jumingo.com/de-de/users/connections/create/8), then create tokens under [My account › API tokens](https://www.jumingo.com/de-de/users/my-account/api-tokens). A token looks like `jum_` followed by 96 hexadecimal characters and is sent as a Bearer token: ``` Authorization: Bearer jum_INSERT_YOUR_TOKEN ``` Each token has a name and a scope. A **Read** token may only call `GET` operations; a `POST`, `PUT`, `PATCH` or `DELETE` with it is answered with `403`. A **Read & write** token may call every operation. You can create several tokens (one per integration), rotate one (new secret, same name and scope) and revoke it at any time; the secret is shown once when the token is created. An unknown, revoked or expired token is answered with `401`, e.g. `{"message": "Invalid API token"}`. ### API key (legacy) The API key shown under Connections still works in the `X-AUTH-TOKEN` header: ``` X-AUTH-TOKEN: INSERT_YOUR_API_KEY ``` It is a single unscoped key that cannot be rotated. **The API key is deprecated and stops working on 1 July 2027.** Switch your integration to a personal access token before that date. A wrong key is answered with `401` and `{"message": "Invalid credentials."}`. ## HTTP status codes Codes in the `2xx` range mean success, `4xx` an error on the client side (a missing parameter, a validation error, a resource that does not exist or that belongs to another account) and `5xx` an error on our side. HTTP status code | Meaning ---------------- | ------- 200, 201, 204 | Everything worked. Creating operations answer `201`, deleting ones `204`. 400 | The request was rejected. Invalid input comes with a `violations` list, see below. 401 | No valid API key was provided or the account is disabled. 403 | You are not allowed to call this endpoint. 404 | The resource does not exist, or it belongs to another account. 429 | The rate limit of the endpoint is used up. Only the access point search is limited today. 500, 502, 503, 504 | Something went wrong on our side. Contact support if it persists. ## Error responses Every error except `401` is a [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) problem object (`Content-Type: application/problem+json`) with `title`, `detail`, `status` and `type`. Input validation errors (`400`) additionally carry a `violations` array with one entry per invalid field: ```json { "title": "An error occurred", "detail": "shipmentId: This value should not be blank.", "status": 400, "type": "/validation_errors/0=c1051bb4-d103-4f74-8988-acbcafc7fdc3", "violations": [ {"propertyPath": "shipmentId", "message": "This value should not be blank.", "code": "c1051bb4-d103-4f74-8988-acbcafc7fdc3"} ] } ``` Messages are returned in the language of your account. ## Dates and times Values you send (`pickupDate`, `deliveryDate`, `order_date`, …) are `string ` in [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) format, e.g. `2026-11-11T16:11:52Z`; `string ` values are `YYYY-MM-DD`. Timestamps the API returns are **not** RFC 3339. They come in two shapes, named in this reference by the schema of the field: * `LocalDateTime` — `YYYY-MM-DD hh:mm:ss` in the Europe/Berlin time zone (CET/CEST), e.g. `2026-10-21 10:40:31`. Used for `created`, `last_modified`, `modified` and `paymentDate` of shipments and orders. * `MidnightDateTime` — `YYYY-MM-DDThh:mm:ssZ` where only the date part is meaningful, e.g. `2026-10-21T02:00:00Z`. Used for `created` and `modified` of connections and the delivery dates of a rate. Dates nested in a shipment's `dates` object are pre-formatted for display in the language of the account. ## Quickstart Five calls take a shipment from your system to a printable label: create the shipment, fetch its rates, assign one, pay, download the documents. Everything below runs with `curl`; the *Test request* panel next to each operation in the reference does the same from the browser. To work in Postman instead, import the collection and the environment from the *Downloads* menu at the top of this page, select the environment and paste your token into `bearerToken`. > [!NOTE] > There is no sandbox. The calls go to your live account, but nothing is charged before `POST /v1/orders`: create, rate, change and delete as many drafts as you like. Buy the first label by hand and keep the purchase step out of your automation until the integration is verified (see the [go-live checklist](#description/go-live-checklist)). ### 1. Get a token 1. Sign in to your JUMiNGO account and enable the customer API under [Connections](https://www.jumingo.com/de-de/users/connections/create/8). 2. Open [My account › API tokens](https://www.jumingo.com/de-de/users/my-account/api-tokens) and create a token with the scope **Read & write**. Ordering a label is a write. 3. Copy the token now. It is shown once; later you can only rotate or revoke it. Export it for the calls below: ```shell export JUMINGO_TOKEN=jum_INSERT_YOUR_TOKEN ``` ### 2. Create the shipment A domestic parcel from Berlin to Neuss. `details.email` is the e-mail address of your JUMiNGO account (on creation the API sets it to the address of the token's account whatever you send), `reference_number` is your own order number and is printed on the label by most carriers. ```shell curl -X POST https://api.jumingo.com/v1/shipments \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "from_address": { "company": "Test Corp.", "name": "John Doe", "street": "Kurfürstendamm 21", "zip": "10719", "city": "Berlin", "country": "DE", "phone": "+493012345678" }, "to_address": { "name": "Jane Roe", "street": "Markt 2", "zip": "41460", "city": "Neuss", "country": "DE" }, "details": { "content_description": "T-shirts", "value_amount": 200, "value_currency": "EUR", "email": "shipping@testcorp.example", "reference_number": "ORDER-10482", "packaging_type": "parcel" }, "packages": [ { "weight": 2.4, "length": 40, "width": 30, "height": 20 } ] }' ``` ```json { "shipment_id": "s_fb1bc92aba1c4d70a3eaa44d687ae179", "warnings": { "messages": [], "count": 0 } } ``` Keep the `shipment_id`; every later call refers to it. See [Shipments](#description/shipments) for every field and its rules. ### 3. Fetch the rates ```shell curl -X POST https://api.jumingo.com/v1/shipment-rates \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shipmentId": "s_fb1bc92aba1c4d70a3eaa44d687ae179", "packagingTypeId": 7, "filterData": { "timeMin": 0, "timeMax": 1440 }, "settings": { "mode": "m" } }' ``` The response lists one entry per bookable carrier product in `tariffs[]`. For each one read `shipper_tariff_id`, `name`, `price_brutto`, `shippingType` (`1` = collected by a driver, `2` = drop-off at a parcel shop) and the permitted pickup window in `dates.pickup`. Details are in [Rates and pickup](#description/rates-and-pickup). ### 4. Assign the rate Write the chosen tariff onto the shipment. For a pickup rate keep the window inside `dates.pickup` of that tariff; for a drop-off rate (`shipping_type: "shop"`) send both times as `00:00:00`. ```shell curl -X PATCH https://api.jumingo.com/v1/shipments/s_fb1bc92aba1c4d70a3eaa44d687ae179 \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/merge-patch+json" \ -d '{ "rate": { "shipper_tariff_id": "15", "shipping_type": "pickup", "pickup_date": "2026-11-20", "pickup_min_time": "10:00:00", "pickup_max_time": "18:00:00" } }' ``` The response is the full shipment. Its `status` must now be `ready`; a shipment in `missing_data` cannot be ordered, and `import_messages_text` tells you which field is missing or invalid. Fix it with another `PATCH`. Read the pickup date and times back from the response: a date the carrier cannot serve is moved to the next possible day instead of being rejected. ### 5. Check the price and buy `POST /v1/cart/total` returns the price you are about to pay and, in `paymentMethods`, the payment methods your account may use. Pay with one of them. ```shell curl -X POST https://api.jumingo.com/v1/cart/total \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shipmentIds": ["s_fb1bc92aba1c4d70a3eaa44d687ae179"] }' curl -X POST https://api.jumingo.com/v1/orders \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shipmentIds": ["s_fb1bc92aba1c4d70a3eaa44d687ae179"], "method": "rechnung" }' ``` ```json { "success": true, "orderNumber": "2611207EKN", "shipmentIds": ["s_fb1bc92aba1c4d70a3eaa44d687ae179"], "message": null, "...": "..." } ``` A rejected order is an error response (`400`, the reason in `detail`) and nothing is charged. Store the `orderNumber`. Payment methods and the SEPA variant are explained in [Orders, payment and documents](#description/orders-payment-and-documents). ### 6. Download the label Label creation runs in the background and usually takes a few seconds. Poll the documents of the order until `labels` has an entry for your shipment, then decode its Base64 `file`, or download the PDF directly with the document's `reference`: ```shell curl https://api.jumingo.com/v1/orders/2611207EKN/documents \ -H "Authorization: Bearer $JUMINGO_TOKEN" ``` ```json { "labels": { "s_fb1bc92aba1c4d70a3eaa44d687ae179": { "name": "L-2611207EKN-1.pdf", "type": "label", "reference": "2611207EKN-1", "file": "JVBERi0xLjQK..." } }, "...": "..." } ``` ```shell curl -o label.pdf https://api.jumingo.com/v1/orders/2611207EKN/file/label/2611207EKN-1 \ -H "Authorization: Bearer $JUMINGO_TOKEN" ``` From here on, `GET /v1/shipments/{uuid}` carries the carrier's tracking in `tracking`; see [Tracking](#description/tracking). ## Shipments A shipment is one consignment from one sender to one recipient with one or more packages. `POST /v1/shipments` creates it as a draft and returns its id (`s_` followed by 32 hex characters) plus a `warnings` object. Create the draft without a rate and assign one afterwards: which rates exist depends on the addresses and the package data. The minimum request is `from_address`, `to_address`, `details` and at least one entry in `packages`. The reference lists every field with its type; the rules that are not visible from the types follow here. ### How the API validates A draft is allowed to be incomplete, so creation rejects less than you may expect. Three things can happen to a value that breaks a rule: Problem | Result ------- | ------ Wrong type or malformed value: a non-numeric weight, a fractional dimension, an invalid e-mail address, an unknown country, currency or packaging type, a wrong date or time format | `400` with the fields in `violations`. Nothing is created. Text longer than the field allows | The shipment is created, the text is cut to the limit and `warnings` lists each shortened value. A required field is missing or a number is out of range | The shipment is created in status `missing_data`; the invalid value is dropped and `import_messages_text` names the gap. Neither an error nor a warning is returned. So a `201` does not mean the shipment is complete: read `warnings` from the response and the `status` of the shipment before you go on. ### Addresses `from_address` and `to_address` share one structure. Field | Rule ----- | ---- `name` | Required. First and last name of the contact, up to 35 characters. `company` | Up to 35 characters. Some tariffs ship only between companies (`from_company_only`, `to_company_only` on the tariff) or only to private addresses. `street`, `street2` | `street` is required and carries street and house number; both up to 35 characters. `zip` | Required when the country uses postal codes, must be absent when it does not. The rate response flags such countries with `post_code_free: 1` in `countries[]`. `city` | Required, up to 30 characters. `state` | Required for US, CA and VN. US and Canadian states are the two-letter abbreviation (`NY`, `ON`), Vietnamese provinces the full ISO 3166-2 code (`VN-SG`). Do not send it for other countries. `country` | Required, ISO 3166-1 alpha-2 code (`DE`, not `Germany`). `phone` | Up to 35 characters. Required by tariffs with `from_phone_number_required` or `to_phone_number_required`. `settings.email` | On `to_address`: the recipient's e-mail address for carrier notifications and customs. Some international tariffs require it. ### Details Field | Rule ----- | ---- `content_description` | Up to 35 characters, printed on the label and used for customs. Needed for international shipments; use the content of the first customs line item there. `value_amount` | Integer, the goods value of the whole shipment. Needed for international shipments other than documents, where it should equal the sum of the customs line items. `value_currency` | ISO 4217 code for `value_amount`. The customs invoice carries its own `currency`. `email` | The e-mail address of your JUMiNGO account, not the recipient's. On creation the API sets it to the address of the token's account; on `PUT` send it again, because `PUT` replaces all details. `reference_number` | Your own reference, e.g. the shop order number, up to 35 characters. Printed on the label by most carriers and found by the `search` parameter of the list endpoints. `email_tracking`, `email_label_copy` | E-mail addresses that receive the tracking link or a copy of the label when the label is created. Set them before you order. `packaging_type` | One of the types below, for every package of the shipment. Omitted means `parcel`. `hs_tariff_number` | Customs tariff number of the main goods; needed for international shipments other than documents. `extra_insurance_value`, `extra_insurance_type` | Extra transport insurance; always sent together. See [Customs, insurance and export](#description/customs-insurance-and-export). `export_license`, `extra_export_license_number` | Buy the export declaration with the shipment, or pass the number of your own. See the same guide. `insurance_amount`, `insurance_currency` | Internal fields. Do not send them; use `extra_insurance_value`. `settings.use_commercial_invoice` | `true` when your own commercial invoice replaces the JUMiNGO proforma invoice for customs. ### Packages and label format `packages[]` needs at least one entry. Each has `weight` in kg (0.1 to 9,999,999) and `length`, `width`, `height` in whole cm (1 to 99,999); the dimensions decide which tariffs are available and whether volumetric weight applies (`calculate_volume_weight` and `volume_weight_factor` on the tariff, usually 5000). `label_format` (`A4` or `A6`) sits on the shipment, not on the package, and overrides the account default. ### Packaging types All packages of a shipment share the packaging type. The id is what `POST /v1/shipment-rates` takes as `packagingTypeId`. Value | Id | Description ----- | -- | ----------- `parcel` | 7 | A stackable cardboard box. The default. `document` | 1 | Documents. No proforma invoice is created; an international document shipment must be free of duty. `bulk` | 9 | Bulky, unshaped items that need special handling: bags, wooden boxes, buckets, canisters, items with protruding parts. `pallet` | 10 | Euro or one-way pallet, stackable, movable with a standard fork lift. `tires` | 11 | Tyres without a carton, foil-wrapped only. `suitcase` | 14 | A suitcase sent as its own packaging. No compensation claim in case of damage. `n_s_pallet` | 15 | Non-stackable pallet, e.g. a conical load. ### Domestic, EU and international Type | Definition | Extra data ---- | ---------- | ---------- Domestic | Origin country equals destination country. | None beyond the base fields. EU | Both countries are EU members (AT BE BG CY CZ DE DK EE ES FI FR GR HR HU IE IT LT LU LV MT NL PL PT RO SE SI SK). | None beyond the base fields. International | Origin or destination is a country outside the EU customs area; the rate response flags those with `tax_free` in `countries[]`. | `customs_invoice` with currency, export reason and line items; `value_amount`, `content_description`, `hs_tariff_number`. Not for packaging type `document`. The recipient's e-mail address when the chosen tariff asks for it. ### Connections Shipments imported from a shop or marketplace carry a `connection` object with the connection id and the order data. Its `validation_mode` (`strict` or `lax`) is recorded with the shipment and does not change how the request is validated: every creation follows the rules under [How the API validates](#description/shipments) above. The `/v1/connections` endpoints themselves exist for plugin developers; an integration of your own account creates shipments directly. ### Change or delete a draft Call | Behaviour ---- | --------- `PATCH /v1/shipments/{uuid}` | Merges the fields in the body into the shipment and keeps the rest; packages are merged by their position in the list. Also assigns the rate. One exception: `label_format` falls back to the account default unless you send it again. `PUT /v1/shipments/{uuid}` | Replaces `details`, `packages`, the rate and `label_format` with the body: what you omit there is lost, and without a `rate` the shipment goes back to `missing_data`. Addresses, `customs_invoice` and `connection` are kept when omitted. `DELETE /v1/shipments/{uuid}` | Deletes the draft, `204` without a body. Both `PATCH` and `PUT` also accept `billing_address`. Only unpaid shipments can be changed or deleted; once a shipment is part of an order the API rejects all three calls. `update_ordered_delivery_address_allowed` belongs to a function of the JUMiNGO web app, and the API has no call for changing the address of an ordered shipment. When you change addresses, packages or the packaging type, the API requests the assigned rate again: if it is still available it stays assigned with its new price, otherwise it is removed and the shipment becomes `missing_data`. Check `status` and the price after every change. ### Status lifecycle Status | Meaning ------ | ------- `missing_data` | Data is missing or no rate is assigned. The shipment cannot be ordered; `import_messages_text` names the gaps. `ready` | Complete, with a valid rate. The status to order from. `in_progress` | A background operation is running, e.g. the bulk rate selection. `import_progress_status` names the step; do not edit until it is finished. `completed` | Ordered. The label is being created or exists, and the carrier has not scanned the parcel yet (tracking `new` or `notfound`). No longer editable. `in_transit` | On its way (tracking `transit`). `in_delivery` | Out for delivery, or ready for collection by the recipient (tracking `pickup`). `exception` | Needs attention: the carrier reported a problem, stopped reporting, or the parcel waits at a parcel shop (tracking `exception`, `expired`, `parcel_shop`). Read `tracking.data.status` to tell them apart. `undelivered` | A delivery attempt failed (tracking `undelivered`). `delivered` | Delivered. Stop polling. `archived` | Moved to the archive in the account. Up to the order, `status` is the draft state. Once the shipment is ordered it is derived from the tracking state, as the table shows; the [tracking guide](#description/tracking) lists the tracking values. `import_status` is the stored draft state: it equals `status` for `missing_data`, `ready`, `in_progress` and `archived` and stays `completed` after the order, so read `status`. A cancelled shipment has `status: null` and `tracking: null`; treat a `null` status as cancelled. `picked_up` is `false` on every shipment until the tracking shows the parcel moving, so on its own it does not mean a missed pickup. `pickup_status` tracks the re-scheduling of a missed one: `0` none, `1` re-schedule e-mail sent, `2` second pickup scheduled, `3` support informed after a failed second pickup, `4` a new pickup was requested and support arranges it with the carrier. ## Rates and pickup A rate is one carrier product with a price, a transit time and constraints, valid for one concrete shipment. Every rate has a `shipper_tariff_id`; whether that id is bookable for a shipment depends on its addresses, packages and packaging type, so fetch the rates per shipment instead of caching a tariff list. ### Fetch the rates `POST /v1/shipment-rates` takes the `shipmentId` and returns every tariff JUMiNGO can offer for it. Field | Rule ----- | ---- `shipmentId` | Required. A draft in your account. `settings.mode` | Required. `m` for the normal request: the same result as the shipping calculator on jumingo.com, Same Day products included. `single` for one tariff, which then needs `settings.tariffId`; the result is then in `tariff` and `tariffs[]` stays empty. `packagingTypeId` | Send the id of the shipment's packaging type, listed under [Shipments](#description/shipments). It filters the result, and when omitted it is `7` (parcel) whatever the shipment's own type is. `pickupDate`, `pickupDateMode` | The day the shipment is to be sent, RFC 3339. `exact` returns only pickup rates that can still be collected on that day; the default `flex` also returns later ones. `deliveryDate` | Rates whose earliest possible delivery is after this date are left out. `filterData.timeMin`, `filterData.timeMax` | The pickup window you can offer, in minutes after midnight: `0` to `1440` is the whole day. Pickup rates that cannot collect inside it are left out. Send both whenever you send `filterData`. `filterData.priceMax` | Price ceiling, compared with the gross price. `filterData.options[]` | `1` no printer required, `3` pickup today, `4` flexible pickup time, `5` private addresses possible, `6` insurance bookable, `7` tracking available. The fields of a `tariffs[]` entry you will use most: Field | Meaning ----- | ------- `shipper_tariff_id` | The value to write into `rate.shipper_tariff_id`. `shippingType` | `1` collected by a driver, `2` drop-off at a parcel shop. `name` | The carrier product, e.g. `UPS EXPRESS SAVER ®`. Show it to your users. `price_netto`, `price_brutto` | The price for this shipment; `tax_free` and `tax_rate` explain the tax treatment. `transit_time_min`, `transit_time_max`, `delivery_time_until` | Transit time in working days and the latest delivery time of day. `printer_required` | `1` when the sender prints the label. `from_company_only`, `to_company_only`, `from_private_only`, `to_private_only` | Address restrictions. A `to_company_only` rate fails for a private delivery address. `from_phone_number_required`, `to_phone_number_required`, `hs_tariff_number_required` | Fields the shipment must carry before this rate can be bought. `calculate_volume_weight`, `volume_weight_factor` | Whether volumetric weight applies and the divisor, usually 5000. `is_insurable_product`, `is_trackable_product` | Whether extra insurance and tracking are available. `dates.pickup` | The permitted pickup window and its minimum length, see below. Outside `tariffs[]` the response carries `countries[]` with `post_code_free` and `tax_free` per country, the pickup-country holidays, the insurance options and the export declaration price. Read them from the response rather than keeping your own lists. ### Assign a rate Write a `rate` object onto the shipment with `PATCH /v1/shipments/{uuid}`. Field | Rule ----- | ---- `shipper_tariff_id` | A tariff id from the rate response of this shipment. `shipping_type` | `pickup` or `shop`, matching `shippingType` `1` or `2` of the tariff. `pickup_date` | `YYYY-MM-DD`, the collection or drop-off day. A date in the past, on a weekend or holiday or after the cut-off is not rejected: the API moves it to the next possible day. `pickup_min_time`, `pickup_max_time` | `hh:mm:ss`, the collection window. The tariff gives `timeFrom` and `timeUntil` as `hh:mm`, so add the seconds. Send both as `00:00:00` for `shop`. Afterwards the shipment is `ready`, or `missing_data` with the reason in `import_messages_text`. The API asks the carrier system for the tariff again when you assign it and stores what comes back, so read the pickup date and times from the response instead of assuming yours were kept. A shipment whose pickup date has passed cannot be ordered; its `dates_in_the_past` flag is then `true`. ### Pickup rules A pickup rate includes collection at `from_address`. Its limits are readable from `dates.pickup` of the tariff: 1. **Minimum window.** `pickup_max_time` minus `pickup_min_time` is at least `pickupTimeMinPeriodMinutes`. A shorter window removes the rate and the shipment becomes `missing_data`. 2. **Earliest and latest time.** Stay between `timeFrom` and `timeUntil`. A window that reaches beyond them can be cut to the permitted range without an error; one that lies outside removes the rate. 3. **Cut-off and holidays.** `min_pickup_date` is the first day a collection is still possible; after the carrier's cut-off the earliest pickup is the next working day, and the pickup-country holidays are returned with the rates. A drop-off rate (`shop`) needs no driver: the sender hands the parcel in at a parcel shop. `POST /v1/carrier/access-points-search` lists the carrier locations near an address. `carrierCodes` and `onlyOpen` are required; `countryCode`, `radius` (km), `city`, `postCode`, `street` and `state` describe the place. What else is needed depends on the carrier (UPS and DPD need `city`, GLS needs `postCode`), and a missing value is reported in `errors[]` of a normal response, not as an error status. The endpoint is limited to 150 calls per account in 24 hours, so cache the result per address. ### Select the cheapest rate automatically For imports where no one picks a rate, `POST /v1/shipments/cheapest` chooses and assigns one for a list of shipments. > [!WARNING] > The call is asynchronous. It answers `200` with an empty body and does the work in the background: the shipments go to `in_progress` with `import_progress_status: get_rates`, then to `ready` (rate assigned) or `missing_data` (no matching rate). Poll `GET /v1/shipments/{uuid}` until they leave `in_progress`, with a timeout: a shipment whose background job failed can stay in progress. Shipment ids that are not in your account are skipped without an error. ```shell curl -X POST "https://api.jumingo.com/v1/shipments/cheapest?sort=cheapest&shippingType=1" \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shipmentIds": ["s_ca213cb9368c412291b8441c90c95592"], "rateInput": { "pickupDate": "2026-11-20T00:00:00Z", "deliveryDate": "2026-11-24T00:00:00Z", "settings": { "mode": "m" } } }' ``` The query parameters narrow the choice. A value the API does not recognise is ignored, not rejected, so verify the outcome on the shipment. Parameter | Values --------- | ------ `sort` | `fastest` selects the earliest delivery; anything else, including no parameter, selects the cheapest. `shippingType` | `1` pickup, `2` shop. Numeric only. `tariffType` | `Same Day`, `Express`, `Economy`, `Standard`, exactly as written. `carrier` | A carrier name such as `UPS` or `DHL Express`, matched without regard to case. Only carriers enabled for bulk rate selection qualify. Of `rateInput`, the API applies `filterData` and `settings` (use `mode` `m`); the pickup and delivery dates of the search are the ones stored on each shipment. Still send `pickupDate`, `deliveryDate` and `settings` as in the example: a `rateInput` without the dates makes the background job fail. ## Customs, insurance and export International shipments are cleared by customs in the origin and the destination country, and that process is digital: the carrier receives the invoice data as structured fields, not as a scanned document. Supply the full commercial or proforma invoice in `customs_invoice`, and keep the three label fields in `details` consistent with it: take `content_description` and `hs_tariff_number` from the first line item and set `value_amount` to the sum of all line values. ### Customs invoice Field | Rule ----- | ---- `currency` | Send it with every customs invoice. ISO 4217 code of the invoice and the parcel value, transmitted to the carrier. It may differ from your account currency; the JUMiNGO invoice for the order is still issued in the account currency. `exportReason` | Needed before the shipment can be ordered. `Gift`, `Commercial`, `Personal`, `Return`, `Claim`, `Temporary`, `Relocation` or `Sample`. It drives the customs procedure on both sides: use `Return` for goods going back to the exporter and `Temporary` for goods that will re-enter. A wrong reason is the most common cause of unexpected duty, and for a business account `Commercial` requires a commercial invoice, not the proforma invoice. `invoiceNumber`, `invoiceDate` | Number and date (`YYYY-MM-DD`) of your own commercial invoice; needed when `details.settings.use_commercial_invoice` is `true`. Leave them empty when the JUMiNGO proforma invoice is used. `remarks[]` | Up to three free-text lines printed on the invoice. `lineItems[]` | Required. One entry per distinct article. `useJumingoCommercialInvoice` | `true` lets JUMiNGO generate the commercial invoice from the line items and send it to the carrier; needs `details.settings.use_commercial_invoice: true` and a packaging type other than `document`. `discount`, `shippingCosts`, `insuranceCosts` | Amounts shown on the generated invoice, in the invoice currency. Omitted shipping and insurance costs are taken from the JUMiNGO shipment. Line item | Rule --------- | ---- `content` | Plain description of the goods. Avoid vague wording such as "samples" or "parts". `quantity`, `unitOfMeasurement` | The quantity and its unit: `PCS`, `M`, `M2`, `M3`, `L` or `KG`. The unit has no default; a line item without it is rejected with `400`. `value` | Total net value of the line, not the price per piece. `netWeight` | Total net weight of the line in kg. `hsTariffNumber` | Customs tariff number of this line. `manufacturingCountry` | ISO 3166-1 alpha-2 country of manufacture. `merchantProductId`, `manufacturerProductId`, `standardizedProductId` | Your SKU, the manufacturer's part number and the EAN/GTIN. The first two are required for a B2C import into the EU from a third country when the ordering customer is a business; the shipment's `product_identifiers_required` tells you when. ### Your own customs documents If you issue your own commercial invoice or hold your own export declaration, upload the PDF before you order, so that it travels with the label data to the carrier: ```shell curl -X POST https://api.jumingo.com/v1/shipments/s_fb1bc92aba1c4d70a3eaa44d687ae179/file/upload/commercial-invoice \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -F "file=@invoice-10482.pdf" ``` Constraint | Value ---------- | ----- `{type}` | `commercial-invoice`, `export-declaration` or `customs-duty-notice`. An `export-declaration` is not accepted when `details.export_license` is set. Format | A PDF file of up to 10 MB, sent as `multipart/form-data` in the field `file`. Replace | A new upload replaces the earlier file of the same type. Remove | `DELETE` on the same path. Uploaded commercial invoices and export declarations come back in `commercialInvoices` and `exportDeclarations` of the order documents; a customs duty notice is not part of that list. Set `details.settings.use_commercial_invoice: true` so that your invoice replaces the proforma invoice. ### Export declaration For an international shipment collected in Germany an export declaration is mandatory when the invoice total (goods minus discount, plus shipping and insurance costs) reaches the threshold of the invoice currency (1,000 EUR by default) or the total weight of its packages reaches 1,000 kg. Set `details.export_license: true` to buy the declaration from JUMiNGO with the order; the price is `extra_export_license_price_brutto` on the tariff and `export_license_price_brutto` on the shipment. If you already hold a declaration, send its number in `details.extra_export_license_number` instead. ### Extra transport insurance Beyond the carrier's standard liability you can insure the shipment against loss, damage and theft in two variants, `standard` and `premium`. `extra_insurance_value` (a whole amount up to 50,000) and `extra_insurance_type` are always sent together and the insurance is booked with the order. Not every tariff is insurable: check `is_insurable_product`. The surcharge is returned as `extra_insurance_price_netto` and `extra_insurance_price_brutto` on the shipment once a rate is assigned, and `POST /v1/cart/total` sums it in `additionalServicesSeparately`. ## Orders, payment and documents An order is the payment for one or more shipments. `POST /v1/orders` is the only call that costs money; it needs a token with the scope **Read & write**, and every shipment in it must be `ready` with a pickup date that has not passed and a tariff that is still available. If one is not, the whole call answers `400` and nothing is charged. ### Price the cart first `POST /v1/cart/total` takes the `shipmentIds` and an optional `voucherCode` and returns the total with its tax and surcharges, the `paymentMethods` your account may use right now, the full shipments with their insurance and export-declaration prices, and `errorList`, the problems per shipment that would stop the order (`date_in_past`, `time_in_past`, `tariff_not_applied`, `tariff_is_no_longer_available`, `not_ready_status`). A shipment listed there is left out of the total, so an empty `errorList` is part of the check. Call it before every purchase: the price you show is then the price you charge, and you only offer payment methods the account can use. Like every `POST`, it needs a `read_write` token. ### Payment methods Method | Meaning | Available when ------ | ------- | -------------- `rechnung` | Invoice. | Payment on account is enabled for the account. `sammelrechnung` | Collective invoice, issued weekly for all orders of the previous week. | Collective invoicing is enabled for the account; it then replaces `rechnung`. `lastschrift` | SEPA direct debit. The mandate data goes into `data`. | The account is based in Germany, direct debit is enabled and the total is above zero. When the account pays by invoice, `paymentMethods` lists only `rechnung` or `sammelrechnung`; `lastschrift` is listed for accounts without invoice payment. The payment methods of the website (PayPal, card, instant payment) are not offered through the API. If none of the three is enabled, `POST /v1/cart/total` answers `400` with `No payment methods available`: ask support or your key account manager to enable one. ```shell curl -X POST https://api.jumingo.com/v1/orders \ -H "Authorization: Bearer $JUMINGO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "shipmentIds": ["s_fb1bc92aba1c4d70a3eaa44d687ae179"], "method": "lastschrift", "data": { "accountOwner": "Test Corp.", "iban": "DE27100777770209299700", "bic": "NORSDE51", "agreement": true } }' ``` Field | Rule ----- | ---- `shipmentIds` | Required. Shipments in status `ready`, as described above. `method` | Required. One of the methods returned by the cart total. `voucherCode` | Must be valid for the shipments in the order. `data` | Required for `lastschrift`: `accountOwner`, `iban`, `bic` and `agreement: true` as in the SEPA mandate. The response carries `success`, the `orderNumber` and the `shipmentIds`. A rejected order is an error response (`400`, the reason in `detail`), not `success: false`, and no charge is made. Order numbers are the order date as `YYMMDD` plus four characters. `GET /v1/orders` and `GET /v1/orders/{orderNumber}` return them with a `B-` prefix; remove it before you call the documents and file endpoints, which take the bare number only. ### Retries Once an order has gone through, its shipments are `completed`, so a later `POST /v1/orders` for the same shipments is rejected with `400` rather than charged twice. That protection does not cover requests that overlap: a second request sent while the first is still being processed can answer `success: true` without an `orderNumber`, and two overlapping requests are not reliably kept apart. Never send orders for the same shipments in parallel, and on a timeout do not resend: read the shipments back and check their `order` field, or search the orders with `GET /v1/orders?search=`, before you decide whether the order exists. ### Documents `GET /v1/orders/{orderNumber}/documents` returns every document of the order with the file as a Base64 string in `file`; `GET /v1/orders/{orderNumber}/file/{type}/{name}` streams one of them as a PDF download, with `name` being the `reference` the documents endpoint shows for it, e.g. `2611207EKN-1` for the label of the first shipment. Key | Per | Notes --- | --- | ----- `invoices` | order | The JUMiNGO invoice. With collective invoicing it appears about a week after purchase and the same file covers every order of that week. `confirmations` | order | The order confirmation. `labels` | shipment | Keyed by shipment id, one PDF per shipment with the labels of all its packages. `proformas` | shipment | Only for shipments to or from a country outside the EU customs area; never for packaging type `document` or when your own commercial invoice is used. `commercialInvoices`, `exportDeclarations` | shipment | The documents you uploaded, or the ones JUMiNGO generated or filed for you. `exportCertVat` | shipment | The export certificate for VAT purposes, once the carrier confirms the export. Label and document generation is asynchronous. There is no count for labels: poll until `labels` has an entry for every shipment of the order. For the other documents `invoicesCount`, `proformasCount`, `commercialInvoicesCount` and `confirmationsCount` say how many are expected (`invoicesCount` stays `0` with collective invoicing); compare them with the lists. Poll every 30 to 60 seconds rather than in a loop. Decode and store the files; do not fetch them on every page view. ### Orders `GET /v1/orders` lists the orders of your account, `GET /v1/orders/{orderNumber}` returns one with its shipments and, once they exist, their tracking numbers. The filters are described under [Listing, filtering and pagination](#description/listing-filtering-and-pagination). ## Tracking `GET /v1/shipments/{uuid}` carries the carrier tracking in `tracking` once the shipment has a tracking number (`null` before, and `null` again for a cancelled shipment). Until the carrier answers for the first time only the tracking number, the status and the tracking page are filled. The fields to build on: Field | Meaning ----- | ------- `tracking.data.tracking_number` | The carrier tracking number. `tracking.data.status` | The authoritative tracking state, see below. `tracking.data.steps[]` | The individual scans with date, time, type and location. `tracking.data.carrier` | The carrier with its `code`, `name` and logo (`image`). `tracking.progress.percent` | A coarse progress indicator for your own UI: `0`, `33`, `66` or `100`. It can go back, e.g. on an exception. `tracking.carrierTrackingPage` | A deep link to the carrier's tracking page. Status | Meaning ------ | ------- `new` | The label exists, the carrier has not scanned the parcel yet. `InfoReceived` | The carrier has the shipment data but not the parcel yet. Treat it like `new`. `transit` | On its way. `pickup` | Out for delivery, or ready for collection by the recipient. `parcel_shop` | Waiting at a parcel shop for the recipient. `delivered` | Delivered. Stop polling. `undelivered` | A delivery attempt failed. `exception` | The carrier reported a problem; read the latest step. `notfound` | The carrier does not know the number yet. `expired` | The carrier has not reported for a long time. You can stop polling. Treat a value you do not recognise, or an empty one, as "in progress" rather than failing. The shipment's own `status` is derived from the tracking: `new`, `InfoReceived` and `notfound` give `completed`, `transit` gives `in_transit`, `pickup` gives `in_delivery`, `exception`, `expired` and `parcel_shop` all give `exception`, and `undelivered` and `delivered` keep their names. `delayed` on the shipment is calculated by JUMiNGO, not reported by the carrier: it is `true` when the expected delivery date has passed and the shipment is not delivered. > [!NOTE] > Do not parse the step texts. The `type` and location strings in `steps[]` come straight from the carrier; their wording, language and detail vary by carrier and region and can change at any time. Drive your logic from `tracking.data.status` and show the steps as free text. There are no webhooks yet, so poll: hourly is sufficient for most carriers, and stop once the status is `delivered` or `expired`. To have the tracking link e-mailed, put the recipient's address into `details.email_tracking` before you order; the mail is sent when the label is created. ## Listing, filtering and pagination `GET /v1/shipments` and `GET /v1/orders` return one page at a time: `page` selects the page (starting at 1) and `itemsPerPage` its size, 10 by default and 100 at most. Iterate until a page comes back with fewer items than requested. Both endpoints return a plain JSON array; there is no envelope with a total count. ### Shipments Parameter | Values --------- | ------ `status` | Default `all`. The lifecycle values `missing_data`, `ready`, `in_progress`, `completed`, `in_delivery`, `in_transit`, `exception`, `undelivered`, `delivered`, `archived`, plus the list views `drafts`, `ordered`, `todo`, `isThirdParty` and the import-progress values below. Several values can be combined with commas; an unknown value returns an empty list, not an error. `importProgressStatus` | `checkout`, `get_rates`, `save_changes`, `delete`, `buy`, `buy_in_progress`: the step of a running bulk operation. `created[before]`, `created[after]` | A date such as `2026-11-20`. Only the day counts: `after` starts at 00:00 and `before` ends at 23:59:59 of that day, whatever time you send. A value that is not a date is ignored. `sort[created]` | `asc` or `desc`. `search` | Full-text search across the shipment: shipment and tracking number, `reference_number`, the addresses and the e-mail addresses. At least three characters; with several words every word must match. `orderNumber` | The shipments of one order. `full_team`, `muid[]` | The shipments of the whole team, or of the given team members. Both need the team permission of your account, otherwise the response is `403`. ### Orders Parameter | Values --------- | ------ `paymentMethod[]` | Exact payment method names, e.g. `rechnung`. `paymentStatus` | `1` unpaid, `0` paid. It covers invoice orders (`rechnung`, `sammelrechnung`); `lastschrift` orders match neither value. `created[before]`, `created[after]` | Date bounds, with the same day rule as for shipments. `sort[created]`, `sort[gross]`, `sort[orderNumber]`, `sort[unpaid]` | `asc` or `desc`. `search` | The same search as for shipments, over the shipments of each order: shipment and tracking number, `reference_number`, pickup code, sender, recipient and billing address, and the tracking and label-copy e-mail addresses. At least three characters. `export` | Marks the response as a file download (`Content-Disposition: attachment`). The content stays in the format you requested. ### Dates in filters and responses Values you send are RFC 3339 (`2026-11-20T00:00:00Z`) or plain dates (`2026-11-20`). Timestamps the API returns are not RFC 3339: `created` and `last_modified` of a shipment and `created`, `modified` and `paymentDate` of an order are `YYYY-MM-DD hh:mm:ss` in the Europe/Berlin time zone (an order that is not paid yet shows the time of your request in `paymentDate`, so read `unpaid` to know whether it is paid), and the dates of connections and rates are `YYYY-MM-DDThh:mm:ssZ` with only the date part meaningful. The *Dates and times* section at the top of this reference names the schema of every such field. ## Tokens and scopes Every v1 request carries exactly one credential: a personal access token in `Authorization: Bearer `, or, for existing integrations, the legacy API key in `X-AUTH-TOKEN`. When both headers are present the Bearer token is used and the key is ignored. The *Authentication* section at the top of this reference shows the headers; this guide covers how to run tokens in production. ### Create and store Tokens are created under [My account › API tokens](https://www.jumingo.com/de-de/users/my-account/api-tokens) after the customer API is enabled under Connections. Each has a name of up to 255 characters and a scope. The secret, `jum_` followed by 96 lowercase hex characters, is shown once; JUMiNGO stores a hash and a short prefix, so a lost token can only be rotated or replaced. An account may hold up to 100 active tokens. A `read_write` token authorises label purchases billed to your account, so treat it like a password: keep it server-side in a secret store, never in browser or app code, never in a repository, never in logs. Issue one token per system (shop, ERP, warehouse, staging) so that you can revoke one without disturbing the others. ### Scopes Scope | Allows ----- | ------ `read` (default) | `GET` only. Any `POST`, `PUT`, `PATCH` or `DELETE` is answered with `403` and the `detail` `This integration token is read-only.`; the operation itself is not carried out. `read_write` | Every operation, including creating shipments and buying labels. The scope is fixed at creation; to change it, create a new token and revoke the old one. Use `read` for jobs that only synchronise tracking or export data: a read-only token cannot spend money. Note that `POST /v1/shipment-rates`, `POST /v1/cart/total` and `POST /v1/carrier/access-points-search` are writes in this sense although they change nothing billable, so the part of your integration that prices shipments needs `read_write` too. ### Lifecycle Event | Behaviour ----- | --------- Revoke | Immediate. Every later call answers `401` with `{"message": "API token has been revoked"}`. Rotate | A new secret for the same token: name and scope are kept, and the old secret stops working the moment the new one is shown (it then answers `Invalid API token`). There is no overlap, so calls fail until the new secret is deployed. To switch without downtime, create a second token, deploy it and revoke the old one. Expiry | Tokens created in the account do not expire; rotate them on your own schedule. An expired token answers `401` with `{"message": "API token has expired"}`. Unknown or malformed | `401` with `{"message": "Invalid API token"}`. A token that does not match the `jum_` shape is rejected before any lookup, so a truncated copy fails fast. Account | If the owning account is deactivated, its tokens answer `401` with `{"message": "API token owner is not available"}`. ### Migrate from the API key The legacy API key stops working on 1 July 2027. 1. Create a token with the scope your integration needs. 2. Replace the header `X-AUTH-TOKEN: ` with `Authorization: Bearer `. Nothing else changes: same base URL, same payloads, same responses. 3. Verify with a cheap read such as `GET /v1/shipments?itemsPerPage=1`. 4. Remove the key from your configuration. ## Errors, limits and troubleshooting The status codes and the error format are described at the top of this reference. A `400` caused by validation lists the failed fields in `violations`, so surface all of them at once instead of the first only; other `400` responses carry the reason in `detail` alone. ### Warnings on shipment creation `POST /v1/shipments` returns a `warnings` object next to the shipment id. A text that is longer than its field allows does not fail the request: it is cut to the limit and listed in `warnings`. Log the warnings and show them to the user before the purchase: a silently shortened address is a failed delivery. Missing fields and out-of-range numbers are not listed there; they leave the shipment in `missing_data` with the reason in `import_messages_text` (see [Shipments](#description/shipments)). ### Rate limits Limits are applied per endpoint and per account. Exceeding one answers `429` with the `detail` `API rate limit exceeded for: `. The response headers `_api_rate_limit_info`, `_api_rate_remaining_info` and `_api_rate_reset_info` carry the limit, the remaining calls and, on a `429`, the time the limit resets as a Unix timestamp. Endpoints without a limit send `0` in all three, so do not read a `0` there as "used up". Endpoint | Limit -------- | ----- `POST /v1/carrier/access-points-search` | 150 calls per account and 24 hours. Cache the access points per address. Other v1 endpoints | No individual cap today. Limits are configuration and can be introduced without a new API version, so handle `429` on every call: back off exponentially with jitter, and never retry `POST /v1/orders` blindly. ### Common failures Symptom | Cause and fix ------- | ------------- `401` on every call | The header is wrong. It is `Authorization: Bearer ` with a capital `B` and one space; the legacy header is `X-AUTH-TOKEN` with the bare key and no `Bearer` prefix. `401 No API token provided` | Neither header arrived, or the scheme is not spelled `Bearer`. `401 Invalid credentials.` | The legacy key in `X-AUTH-TOKEN` is unknown. `401 Invalid API token` | The token is unknown or truncated. Check it in your account and copy it in full. `401 API token has been revoked` | The token was revoked in the account. Create a new one. `401 API token has expired` | The token passed its expiry date. Create a new one. `403` on writes only | The token has the scope `read`. Issue a `read_write` token; the rate, cart-total and access-point calls are `POST` and need it too. `403` with `full_team` | Your account lacks the team permission. No rates returned | The address or package data excludes every tariff. Check the postcode rule of the country, that `state` is set for US, CA and VN only, that `packagingTypeId` is the shipment's packaging type, and that `filterData` carries both `timeMin` and `timeMax`. Shipment `missing_data` after assigning a rate | The tariff is not valid for this shipment or the pickup window breaks a rule. Fetch the rates again and read `dates.pickup`. Cheapest call "did nothing" | It is asynchronous. Poll the shipments until they leave `in_progress`; `missing_data` means no rate matched the filters. Cheapest filter ignored | `shippingType` takes `1` or `2`, `tariffType` is case-sensitive. Unknown values are dropped silently. Order rejected with `Some shipments are missing or have the wrong status!` | A shipment is not `ready`, its pickup date has passed or its tariff is no longer available. `errorList` of `POST /v1/cart/total` names the reason per shipment. Payment method rejected | The method is not enabled for the account. Offer only what `POST /v1/cart/total` returns. Documents still empty | Generation is asynchronous. Poll until `labels` has an entry for every shipment, and compare the other lists with the `*Count` fields. Pickup date changed | A date in the past, on a non-working day or after the cut-off is moved to the next possible day when the rate is assigned. Read the date back from the response and check `min_pickup_date` on the tariff. Order endpoint answers `404` for a number from the order list | The list returns the number with a `B-` prefix; the documents and file endpoints take it without. Address silently shortened | A value was longer than its field allows and was cut on creation. Read `warnings` and keep to the lengths under [Shipments](#description/shipments). Upload rejected | Only a PDF file, only the types `commercial-invoice`, `export-declaration` and `customs-duty-notice`, not while the shipment is `in_progress` or archived, and no `export-declaration` when `details.export_license` is set. ## Go-live checklist Work through this list before you let your integration buy labels on its own. There is no sandbox, so every step runs against your live account; drafts are free, and only the last two items place a chargeable order. Item | What to verify ---- | -------------- Bearer migration | No code path still sends `X-AUTH-TOKEN`. Token handling | Tokens live server-side in a secret store and never appear in logs. One token per system. Scope | Read-only jobs (tracking sync, exports) use a `read` token; only the purchasing path holds `read_write`. Token replacement drill | You have replaced a token once without downtime: second token created and deployed, old one revoked. Domestic shipment | Create, rate, assign, status `ready`, then delete the draft. EU shipment | The same flow with a cross-border EU address pair. International shipment | A full `customs_invoice` with line items; `value_amount` equals the sum of the line values. Postcode-free country | No `zip` for a country with `post_code_free: 1`, and the request is accepted. US, CA and VN addresses | `state` is present for those three countries and absent everywhere else. Multi-package shipment | Several packages, one packaging type, correct total weight. Drop-off rate | A `shop` rate with both pickup times `00:00:00`. Pickup window | The window respects `pickupTimeMinPeriodMinutes` and the cut-off. Bulk rating | If you use `POST /v1/shipments/cheapest`, your code polls to completion and handles `missing_data`. Validation errors | Your code reads every entry in `violations`, every message in `warnings` and the `status` of each shipment it created. Rate limits | `429` is caught and retried with backoff, not treated as a hard failure. Retry safety | No code path calls `POST /v1/orders` twice for the same basket, in parallel or after a timeout, without checking the shipments first. Price check | `POST /v1/cart/total` runs before every purchase and its total is what you show. Document polling | Polling with backoff, a stop condition and an alert if documents never arrive. Tracking polling | Driven by `tracking.data.status`, stopping at `delivered` or `expired`. First live order | One real shipment, bought by hand, label printed and handed to the carrier. Reconciliation | Your records match the JUMiNGO invoice for that first order. ### Glossary Term | Meaning ---- | ------- Shipment | One consignment from one sender to one recipient with one or more packages; id `s_…`. Draft | A shipment that has not been paid for. Editable and deletable. Rate, tariff | A carrier product with price, transit time and constraints, valid for one shipment; `shipper_tariff_id`. Order | A payment covering one or more shipments; order number `YYMMDD` plus four characters. Personal access token | A named, scoped, revocable Bearer credential of one account. Scope | What a token may do: `read` or `read_write`. Access point | A carrier location where a parcel is dropped off or collected. Connection | A link between a JUMiNGO account and a shop or marketplace. Plugin developers only. Proforma invoice | The customs document JUMiNGO generates for an international shipment when you supply no commercial invoice. Export declaration | The customs filing for higher-value or heavy exports from Germany. Volumetric weight | Chargeable weight derived from the dimensions divided by the tariff's `volume_weight_factor`, usually 5000. Cut-off | The latest moment a rate can still be applied for same-day collection. Questions about your integration: write to [connections@jumingo.com](mailto:connections@jumingo.com) or contact your key account manager. ## Operations ### GET /v1/shipments List shipments. Gets a list of all shipments. You can filter and sort the shipments. The pagination is done by limit and offset parameters. - `full_team` (query): `1` lists the shipments of the whole team instead of your own. Needs the team permission of your account, otherwise the response is 403. - `muid[]` (query): Customer numbers of team members whose shipments to use instead of your own. Needs the team permission of your account. - `status` (query): Status of shipments - `importProgressStatus` (query): Import Progress Status of shipments - `created[before]` (query): Filter by created before the date. For example: "2020-09-19". Only the date part is used: `before` includes the whole day, `after` starts at 00:00. - `created[after]` (query): Filter by created after the date. For example: "2020-09-19". Only the date part is used: `before` includes the whole day, `after` starts at 00:00. - `sort[created]` (query): Sort by created. For example: "asc" - `sort[modified]` (query): Accepted for compatibility and ignored; the list can only be sorted by `created`. - `search` (query): Full text search over shipment number, tracking number, reference number, the addresses and the e-mail addresses of the shipment. At least three characters; with several words every word must match. - `orderNumber` (query): Filter shipments by orderNumber - `page` (query): The collection page number - `itemsPerPage` (query): The number of items per page - `pagination` (query): Client enable pagination - 200: One page of shipments - 400: - 401: - 403: ### POST /v1/shipments Create a shipment. Creates a new shipment. If you are using an e-commerce connection, you must specify the order data with "connection_custom_data". Request body: `application/json`, schema `CreateShipment`. - 201: The shipment was created - 400: - 401: - 403: ### GET /v1/shipments/{uuid} Get a shipment. Get a specific shipment based on the given shipment ID. - `full_team` (query): `1` lists the shipments of the whole team instead of your own. Needs the team permission of your account, otherwise the response is 403. - `muid[]` (query): Customer numbers of team members whose shipments to use instead of your own. Needs the team permission of your account. - `uuid` (path, required): The shipment id. - 200: The shipment - 401: - 403: - 404: ### PUT /v1/shipments/{uuid} Replace a shipment. Stores the given data as the whole shipment. Only possible until the shipment is ordered. - `uuid` (path, required): The shipment id. Request body: `application/json`, schema `UpdateShipment`. - 200: The updated shipment - 400: - 401: - 403: - 404: ### PATCH /v1/shipments/{uuid} Update parts of a shipment. Merges the given sections into the shipment (JSON merge patch). Only possible until the shipment is ordered. - `uuid` (path, required): The shipment id. Request body: `application/merge-patch+json`, `application/json`, schema `PatchShipment`. - 200: The updated shipment - 400: - 401: - 403: - 404: ### DELETE /v1/shipments/{uuid} Delete a shipment. - `uuid` (path, required): The shipment id. - 204: The shipment was deleted - 400: - 401: - 403: - 404: ### POST /v1/shipments/cheapest Select the cheapest rate for shipments. Chooses and assigns a rate for each shipment in the background. The shipments go to `in_progress` with `import_progress_status` `get_rates` and end as `ready` (rate assigned) or `missing_data` (no matching rate); poll them to see the outcome. Shipment ids of other accounts are skipped. - `shippingType` (query): Rate shipping type: `1` collected by a driver, `2` drop-off at a parcel shop. Numeric only; other values are ignored. - `tariffType` (query): Rate tariff type - `carrier` (query): Rate carrier - `sort` (query): Results sorting Request body: `application/json`. - 200: The selection was started; it runs in the background. The response has no body. - 400: - 401: - 403: ### POST /v1/shipments/{uuid}/file/upload/{type} Upload a customs document. - `uuid` (path, required): The shipment id. - `type` (path, required): The document type. `export-declaration` is not accepted when the shipment books the export declaration (`details.export_license`). A new upload replaces the earlier file of the same type. Request body: `multipart/form-data`. - 201: The document was stored - 400: - 401: - 403: - 404: ### DELETE /v1/shipments/{uuid}/file/upload/{type} Delete a customs document. - `uuid` (path, required): The shipment id. - `type` (path, required): The document type. - 204: The document was deleted - 400: - 401: - 403: - 404: ### POST /v1/shipment-rates Get the rates for a shipment. With this endpoint you can fetch available shipment rates for a given shipment. It is necessary to include a valid shipmentId in the request body. Best practice is to create a shipment first, including the sender and delivery address, the packaging type and all package dimensions. The returned shipment ID can be used in the shipment-rates call to get all available rates for this shipment from the JUMiNGO system. **Minimum input** replace shipment id with shipment from your account to receive available rates. Although it is not required to include the packaging type ID in the request, the results will be more relevant if you add one. ``` { "shipmentId":"s_2b28a63d65684f0aa4bcca24dafdc9df", "filterData": { "timeMax": 1440, "timeMin": 0 }, "settings":{ "mode":"m" } } ``` **Get data for a single rate** replace shipment id with shipment from your account and valid tariffId that is suitable for this shipment id ``` { "shipmentId": "s_2b28a63d65684f0aa4bcca24dafdc9df", "filterData": { "timeMax": 1440, "timeMin": 0 }, "settings": { "mode": "single", "tariffId": "s-420" } } ``` - `full_team` (query): `1` lists the shipments of the whole team instead of your own. Needs the team permission of your account, otherwise the response is 403. - `muid[]` (query): Customer numbers of team members whose shipments to use instead of your own. Needs the team permission of your account. Request body: `application/json`, schema `ShipmentRateInput`. - 201: The available rates - 400: - 401: - 403: - 404: ### POST /v1/cart/total Get the cart total. Get cart total costs with a description of the calculations Request body: `application/json`, schema `CartTotalInput`. - 201: Totals, available payment methods and per-shipment problems - 400: - 401: - 403: - 404: ### GET /v1/orders List orders. - `full_team` (query): Accepted for compatibility with the shipment endpoints and ignored; the list always contains your own orders. - `export` (query): Marks the response as a file download (`Content-Disposition: attachment`). The content stays in the requested format. - `paymentMethod[]` (query): Filter by array of exact payment method names. For example: ["paypal", "sofort"] - `paymentStatus` (query): Filter by payment status, `1` for unpaid and `0` for paid. Covers invoice orders (`rechnung`, `sammelrechnung`); `lastschrift` orders match neither value. - `created[before]` (query): Filter by created before the date. For example: "2020-09-19". Only the date part is used: `before` includes the whole day, `after` starts at 00:00. - `created[after]` (query): Filter by created after the date. For example: "2020-09-19". Only the date part is used: `before` includes the whole day, `after` starts at 00:00. - `sort[created]` (query): Sort by created. For example: "asc" - `sort[gross]` (query): Sort by gross. For example: "desc" - `sort[orderNumber]` (query): Sort by orderNumber. For example: "asc" - `sort[unpaid]` (query): Sort by unpaid. For example: "desc" - `search` (query): Full text search over the shipments of each order: shipment number, tracking number, reference number, pickup code, sender address (return address), recipient address, billing address and e-mail address (email_label_copy or email_tracking). At least three characters. - `page` (query): The collection page number - `pagination` (query): `false` returns every matching order in one response instead of a page. - `itemsPerPage` (query): The number of items per page, 10 by default - 200: One page of orders; with `export` the same content as a file download - 400: - 401: ### POST /v1/orders Pay for shipments. Pays for the given shipments with the chosen payment method and creates the order. The shipments must have a rate and complete data; `POST /v1/cart/total` tells you beforehand which payment methods the account may use and which shipments still have problems. Request body: `application/json`, schema `PaymentInput`. - 201: The payment succeeded or was started - 400: - 401: - 403: ### GET /v1/orders/{orderNumber} Get an order. - `orderNumber` (path, required): The order number, with or without its `B-` prefix. - 200: The order - 401: - 404: ### GET /v1/orders/{orderNumber}/documents Get the documents of an order. - `orderNumber` (path, required): The order number without the `B-` prefix that the order list and `GET /v1/orders/{orderNumber}` return; a prefixed number is not found. - 200: The documents of the order - 401: - 404: ### GET /v1/orders/{orderNumber}/file/{type}/{name} Download a document of an order. Streams one document of the order as a PDF download. `name` is the `reference` the documents endpoint returns for the document, e.g. `2611207EKN-1` for the label of the first shipment. For `commercial-invoices` the document always covers the order in the path, so any value is accepted as `name`, e.g. the order number. - `orderNumber` (path, required): The order number without the `B-` prefix that the order list and `GET /v1/orders/{orderNumber}` return; a prefixed number is not found. - `type` (path, required): The document type. - `name` (path, required): The reference of the document, as returned in the documents of the order. - 200: The document as a file download; `Content-Disposition` carries the file name. - 400: - 401: - 404: ### GET /v1/connections List connections. - `status` (query): Status of connections - `connectionType` (query): Connection type ID - `sort[status]` (query): Sort by status - `sort[connectionType]` (query): Sort by connectionType - `sort[modified]` (query): Sort by modified - `page` (query): The collection page number - `itemsPerPage` (query): The number of items per page - 200: One page of connections - 400: - 401: ### POST /v1/connections Create a connection. Creates a new connection. **This API call is for e-commerce / shop plugin developers only.** As a registered plugin developer, you have received additional, separate information for this call. If you would like to create a new shop plugin, please contact our customer support for more information. Request body: `application/json`, schema `CreateConnection`. - 201: The connection was created - 400: - 401: - 403: ### GET /v1/connections/{uuid} Get a connection. - `uuid` (path, required): The connection id. - 200: The connection - 401: - 404: ### POST /v1/carrier/access-points-search Search carrier access points. Lists the carrier locations near an address. Which address fields a search needs depends on the carrier (UPS and DPD need `city`, GLS needs `postCode`); a missing one is reported per carrier in `errors` of the response, not as an error status. Limited to 150 calls per account in 24 hours. Request body: `application/json`. - 201: The access points per carrier - 400: - 401: - 403: - 429: The rate limit of 150 calls per account in 24 hours is used up