Parcels, addresses and carriers
These routes are the logistics part of the E-commerce API. They let your own software add the parcels you want to follow, keep your address book in step with your other tools and read the carrier catalogue. They work on the same records as the Logistics screens of your workspace: a parcel created by the API appears in your parcel list, and an address added on screen can be read here.
A key reads and writes the address book and the parcels of the account it belongs to, and nothing else. The carrier catalogue is shared and read-only.
Endpoints
| Method | Path | Scope |
|---|---|---|
| GET | /v1/carrier/list | carrier:read |
| GET | /v1/carrier/detail/carr_… | carrier:read |
| GET | /v1/parcel/list | parcel:read |
| GET | /v1/parcel/detail/parc_… | parcel:read |
| POST | /v1/parcel/create | parcel:write |
| PATCH | /v1/parcel/detail/parc_… | parcel:write |
| DELETE | /v1/parcel/detail/parc_… | parcel:write |
| GET | /v1/address/list | address:read |
| GET | /v1/address/detail/addr_… | address:read |
| POST | /v1/address/create | address:write |
| PATCH | /v1/address/detail/addr_… | address:write |
| DELETE | /v1/address/detail/addr_… | address:write |
The lists take limit (50 by default, 100 at most) and offset, and answer total, limit, offset and data. Authentication, the response envelope and the error format are those of Your first call.
Carriers
Read the catalogue to find the carrier of a parcel: you pass its id as carrier_id when you create the parcel.
GET /v1/carrier/list accepts these filters:
| Parameter | Description |
|---|---|
q | Part of the carrier's name, code or tracking code. |
code | The carrier's tracking code, digits only. |
country | A two-letter country code. |
source | 17track or manual. |
The carrier object
| Field | Type | Description |
|---|---|---|
id | string | The carrier's identifier, prefixed carr_. |
object | string | Always carrier. |
status | string | The carrier's status in the catalogue. |
name | string | The carrier's name. |
code | string | The carrier's short code. |
tracking_code | string | The carrier's tracking code; you may pass it as carrier_code instead of carrier_id. |
country | string | The carrier's country, as a lowercase two-letter code. |
website | string | The carrier's website. |
tracking_url | string | The carrier's public tracking page. |
logo | string or null | The address of the carrier's logo. |
contact | object | email and phone. |
source | string | 17track or manual. |
created_at, updated_at | integer | Unix timestamps. |
Parcels
Follow a parcel
POST /v1/parcel/create adds one parcel and answers 201 with the parcel.
| Field | Required | Description |
|---|---|---|
tracking_number | Yes | The carrier's tracking number, 5 to 50 characters; spaces are dropped. |
carrier_id | Yes, or carrier_code | The carrier's id, from the carrier list. |
carrier_code | Yes, or carrier_id | The carrier's tracking_code. |
label | No | Your own name for the parcel, 200 characters at most. |
recipient_id | No | An address of your book, prefixed addr_. |
shipment_id | No | A shipment of your shop, prefixed ship_. |
origin, destination | No | A place name, 200 characters at most. |
origin_country, destination_country | No | Two-letter country codes. |
weight, weight_unit | No | The weight and its unit; kg when no unit is given. |
content | No | What the parcel holds, 255 characters at most. |
note | No | A free note. |
added_at | No | A Unix timestamp, to keep the date of a parcel that comes from another tool. |
curl -X POST https://api.ultineo.com/v1/parcel/create \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"tracking_number": "1Z999AA10123456784",
"carrier_code": "100002",
"label": "Order 1042"
}' A tracking number already followed in your book is not followed twice: the answer is 409 and carries the id of the parcel that holds it.
To add several parcels in one call, send them under items, 100 at most:
{
"items": [
{ "tracking_number": "1Z999AA10123456784", "carrier_code": "100002" },
{ "tracking_number": "LX123456789FR", "carrier_id": "carr_4f1c2a9d8e7b6a5c4d3e" }
]
} The answer lists one entry per item, in order, with its tracking_number and either action (created or existing) and id, or code and reason when the item was refused. It ends with the counts created, existing, refused and total. The status is 200 when at least one parcel was created or already existed, and 422 when every item was refused. More than 100 items answers 413.
How tracking fills a parcel in
A parcel starts with the status pending. Ultineo then registers its number with the carrier in the background and writes the result on the parcel: its status in the carrier's own words (such as InTransit or Delivered), its last location, its estimated and actual delivery dates, and one event per checkpoint. Nothing is returned by the create call itself: read the parcel again, or sync the list.
The parcel object
| Field | Type | Description |
|---|---|---|
id | string | The parcel's identifier, prefixed parc_. |
object | string | Always parcel. |
label | string | Your own name for the parcel. |
status, substatus | string | pending at first, then the carrier's status. |
tracking | object | number, carrier_code, registration (the state of the registration with the carrier), state (active or paused), attempts and synced_at. |
carrier | object or null | id, name and logo. |
recipient | object or null | The id of the address. |
shipment | object or null | The id of the shipment. |
origin, destination | object | place and country. |
weight | object | value and unit. |
content, note | string | As you sent them. |
progress | object | last_status_code, last_location, last_lat, last_lng, last_event_at, estimated_delivery_at and delivered_at. |
created_at, updated_at | integer | Unix timestamps. |
GET /v1/parcel/detail/parc_… also returns events, the parcel's checkpoints, newest first. Each event carries id, type, description, location, lat, lng and occurred_at.
List and sync parcels
GET /v1/parcel/list accepts these filters: status, tracking_number, carrier (a carr_… identifier), recipient (an addr_… identifier), shipment (a ship_… identifier) and q, which searches the label, the number, the carrier, the destination and the recipient's names.
To follow changes without reading everything again, sync the list:
- Call
GET /v1/parcel/list?updated_since=<Unix timestamp>once. - Store the
cursorof the answer. - Call
GET /v1/parcel/list?cursor=<cursor>next time, and store the newcursor.
While next_cursor is not null, more rows are waiting: call again with it at once. A sync takes no offset.
Change or delete a parcel
PATCH /v1/parcel/detail/parc_… changes the fields the body names and leaves the others as they are. Two fields are specific to it:
| Field | Description |
|---|---|
refresh | true asks the carrier again at the next pass. |
tracking | paused stops following the parcel, active resumes. |
Changing the tracking number or the carrier registers the parcel again, and its status goes back to pending. An archived parcel can no longer be changed.
DELETE /v1/parcel/detail/parc_… removes the parcel from your lists and answers { "id": "parc_…", "object": "parcel", "deleted": true }.
Addresses
Add an address
POST /v1/address/create adds an entry to your address book and answers 201.
| Field | Required | Description |
|---|---|---|
role | Yes | sender or recipient. |
phone | Yes | The contact's phone number. |
line1 | Yes | The first address line. |
postal_code | Yes | The postal code. |
city | Yes | The city. |
country | Yes | A two-letter country code. |
type | No | individual (default) or company. |
company | No | The company name, kept for a company entry only. |
first_name, last_name | No | The contact's name. |
email | No | The contact's e-mail address. |
phone_country | No | The country the phone number is read in; the address's country by default. |
line2 | No | The second address line. |
state | No | The state or region, kept only for a country that uses one. |
label | No | Your own name for the entry. |
is_default | No | true makes it the default entry of its role. |
note | No | A free note. |
The phone number, and the e-mail address when there is one, are checked before anything is stored, and the entry keeps their normalised form. An invalid value answers 422. If the check cannot be made, the answer is 503 and nothing is stored: send the request again later.
The same contact name at the same postal code is not stored twice: the answer is 409 and carries the id of the entry that already holds it.
The address object
| Field | Type | Description |
|---|---|---|
id | string | The entry's identifier, prefixed addr_. |
object | string | Always address. |
status | string | activated, suspended or archived. |
role | string | sender or recipient. |
type | string | individual or company. |
label, company | string | As you sent them. |
contact | object | name, first_name, last_name, email and phone. |
location | object | line1, line2, postal_code, city, state and country. |
is_default | boolean | Whether it is the default entry of its role. |
note | string | Your note. |
created_at, updated_at | integer | Unix timestamps. |
List, change or delete an address
GET /v1/address/list accepts these filters: role, status, country, default=true and q.
PATCH /v1/address/detail/addr_… changes the fields the body names. It also takes status, activated or suspended. There is at most one default entry per role and only an activated entry can be it: marking one clears the others, and suspending the default entry drops its mark. An archived entry must be reactivated before it is changed.
DELETE /v1/address/detail/addr_… removes the entry from your book and answers { "id": "addr_…", "object": "address", "deleted": true }.