ULTINEO

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

MethodPathScope
GET/v1/carrier/listcarrier:read
GET/v1/carrier/detail/carr_…carrier:read
GET/v1/parcel/listparcel:read
GET/v1/parcel/detail/parc_…parcel:read
POST/v1/parcel/createparcel:write
PATCH/v1/parcel/detail/parc_…parcel:write
DELETE/v1/parcel/detail/parc_…parcel:write
GET/v1/address/listaddress:read
GET/v1/address/detail/addr_…address:read
POST/v1/address/createaddress: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:

ParameterDescription
qPart of the carrier's name, code or tracking code.
codeThe carrier's tracking code, digits only.
countryA two-letter country code.
source17track or manual.

The carrier object

FieldTypeDescription
idstringThe carrier's identifier, prefixed carr_.
objectstringAlways carrier.
statusstringThe carrier's status in the catalogue.
namestringThe carrier's name.
codestringThe carrier's short code.
tracking_codestringThe carrier's tracking code; you may pass it as carrier_code instead of carrier_id.
countrystringThe carrier's country, as a lowercase two-letter code.
websitestringThe carrier's website.
tracking_urlstringThe carrier's public tracking page.
logostring or nullThe address of the carrier's logo.
contactobjectemail and phone.
sourcestring17track or manual.
created_at, updated_atintegerUnix timestamps.

Parcels

Follow a parcel

POST /v1/parcel/create adds one parcel and answers 201 with the parcel.

FieldRequiredDescription
tracking_numberYesThe carrier's tracking number, 5 to 50 characters; spaces are dropped.
carrier_idYes, or carrier_codeThe carrier's id, from the carrier list.
carrier_codeYes, or carrier_idThe carrier's tracking_code.
labelNoYour own name for the parcel, 200 characters at most.
recipient_idNoAn address of your book, prefixed addr_.
shipment_idNoA shipment of your shop, prefixed ship_.
origin, destinationNoA place name, 200 characters at most.
origin_country, destination_countryNoTwo-letter country codes.
weight, weight_unitNoThe weight and its unit; kg when no unit is given.
contentNoWhat the parcel holds, 255 characters at most.
noteNoA free note.
added_atNoA Unix timestamp, to keep the date of a parcel that comes from another tool.
curl
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:

application/json
{
  "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

FieldTypeDescription
idstringThe parcel's identifier, prefixed parc_.
objectstringAlways parcel.
labelstringYour own name for the parcel.
status, substatusstringpending at first, then the carrier's status.
trackingobjectnumber, carrier_code, registration (the state of the registration with the carrier), state (active or paused), attempts and synced_at.
carrierobject or nullid, name and logo.
recipientobject or nullThe id of the address.
shipmentobject or nullThe id of the shipment.
origin, destinationobjectplace and country.
weightobjectvalue and unit.
content, notestringAs you sent them.
progressobjectlast_status_code, last_location, last_lat, last_lng, last_event_at, estimated_delivery_at and delivered_at.
created_at, updated_atintegerUnix 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:

  1. Call GET /v1/parcel/list?updated_since=<Unix timestamp> once.
  2. Store the cursor of the answer.
  3. Call GET /v1/parcel/list?cursor=<cursor> next time, and store the new cursor.

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:

FieldDescription
refreshtrue asks the carrier again at the next pass.
trackingpaused 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.

FieldRequiredDescription
roleYessender or recipient.
phoneYesThe contact's phone number.
line1YesThe first address line.
postal_codeYesThe postal code.
cityYesThe city.
countryYesA two-letter country code.
typeNoindividual (default) or company.
companyNoThe company name, kept for a company entry only.
first_name, last_nameNoThe contact's name.
emailNoThe contact's e-mail address.
phone_countryNoThe country the phone number is read in; the address's country by default.
line2NoThe second address line.
stateNoThe state or region, kept only for a country that uses one.
labelNoYour own name for the entry.
is_defaultNotrue makes it the default entry of its role.
noteNoA 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

FieldTypeDescription
idstringThe entry's identifier, prefixed addr_.
objectstringAlways address.
statusstringactivated, suspended or archived.
rolestringsender or recipient.
typestringindividual or company.
label, companystringAs you sent them.
contactobjectname, first_name, last_name, email and phone.
locationobjectline1, line2, postal_code, city, state and country.
is_defaultbooleanWhether it is the default entry of its role.
notestringYour note.
created_at, updated_atintegerUnix 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 }.