Přeskočit na obsah
This guide is designed specifically for developers.

Globe API

Tento obsah zatím není dostupný ve vašem jazyce.

The Globe API gives a server access to the shipping labels of one Shopify store. It reads labels and their PDFs, and it creates labels with the store’s carrier accounts. Requests authenticate with an API key of that store.

Responses are JSON with snake_case fields, ISO 8601 UTC timestamps, and null for missing values. Money amounts are decimal strings with two places, such as "1290.00". Label documents are PDF.


The API is in beta and enabled per store. Ask in the support chat in the Globe admin. Until then, Settings → API says that API access is not enabled, and requests get 403 access_required.

Creating labels needs a second switch for writes. Without it, POST /labels (dry runs included), resolve and mark-printed get 403 write_access_required. Ask support for it when you need it.

The store also needs an active Globe subscription or free access. Otherwise requests get 403 plan_required.

Create keys in Settings → API in the Globe admin.

  • A key belongs to one store. The store comes from the key; no endpoint takes a store parameter.
  • A key looks like glb_live_… and is shown once, when you create it. Globe stores only its hash.
  • A store can have 20 active keys. Use one key per packing station or integration.
  • Rotate creates a new key with the same name and scopes. The old key keeps working for the overlap you choose: none, 24 hours (default) or 7 days.
  • Revoke stops a key at once.
  • Globe emails the store when a key is created, rotated or revoked.
  • Developer console (in Settings → API) lists the store’s API requests for 90 days: endpoint, status, error code, key, IP, and for document downloads the number of labels and the size. Request bodies and query strings are never logged.

Send the key in the Authorization header:

Authorization: Bearer glb_live_…

A key in the query string (?api_key=) is refused with 400 validation_error on every path, /v1/openapi.json included. The API is meant for servers and sends no CORS headers. Never use a key in a browser.

GET /shop returns the store, the key’s scopes and its pinned version. Use it to test a key.

Responses carry these headers:

HeaderDescription
X-Request-IdID of the request (req_…). Send it to support with any question about a call
Globe-VersionThe version the response is rendered in
X-RateLimit-*See Rate limits
Cache-Controlno-store, private. The OpenAPI document is the exception

The API is versioned by date. The current version is 2026-10-01.

  • Send Globe-Version: 2026-10-01 to choose a version per request. Without the header, the version pinned on the key when it was created applies.
  • An unknown version gets 422 unsupported_version.
  • New endpoints, new optional fields and new webhook topics ship in the current version. A breaking change ships only in a new dated version.
  • At most two versions are live at the same time.

The API changelog lists the changes in each version.

When you create a key in Globe → Settings → API, you choose what it may do. A template (print station, warehouse or ERP, overview only) only pre-ticks the choices.

PermissionWhat the key can doScopes
Read labels, orders and pickup points (always on)Find the labels of an order and read their status, tracking number and carrier; read an order’s selected pickup point, reminder e-mails, delivery status and COD; find pickup points near an order’s address. No customer names, addresses, phone numbers or e-mailsshop:read, labels:read, carriers:read, orders:read, pickup_points:read
Print labelsDownload label PDFs (one label, a whole order or up to 50 at once) and mark them printed. The PDF contains the customer’s name, address, phone number and COD amountlabels:print
Change an order’s pickup pointSet or change the pickup point of an order that has no label yet, like “Edit pickup point” in the admin. It replaces the customer’s choice, and the carrier’s settings may change the shipping address to the point’spickup_points:assign
Create labelsCreate shipments at the carrier, dry runs included, and follow label creations. The carrier bills the shipment and Globe cannot cancel itlabels:write
Resolve unclear creationsResolve creations in needs_attention. Only together with Create labels. Give it only to a tool a person operates, not to an automationlabel_creations:resolve

Scopes are exact matches. There is no wildcard. Every key has shop:read, carriers:read, orders:read and pickup_points:read, and labels:print and labels:write include labels:read. A key’s permissions cannot be changed; create a new key instead.

labels:print replaced label_documents:read on 20 October 2026, and marking a label printed moved to it from labels:write. Keys created before that hold labels:print automatically.

RequestsPer keyPer store
Reads: GET /shop, /labels, /label-creations, /carrier-accounts, /orders/{id}, /orders/{id}/pickup-points10/s, 600/min–
Stored label documents120/min300/min
Documents rendered at the carrier–60/min, 3 at once
POST /labels with dry_run2/s, 30/min60/min
POST /labels5/s60/min, 2,000 creations/day, 50 create_new creations/day
POST /label-creations/{id}/resolve1/s30/h
POST /labels/{id}/printed5/s300/min
PUT /orders/{id}/pickup-point2/s120/min
  • A merged PDF counts one document per label.
  • A repeat of a bound Idempotency-Key counts as a read.
  • The daily creation limits count creations that reach the carrier. A request that returns existing labels or is refused before the carrier call gives its unit back.
  • POST /labels also has a queue per store. When too many creations wait, new ones get 429 with bucket write_queue_depth. The queue holds at most 100 creations, fewer when the store’s recent creations were slow.
  • Up to 8 requests per key can hold a Prefer: wait. Further requests answer at once, as with wait=0.
  • Support can change the limits of a store.

The X-RateLimit-* headers describe the tightest bucket of the request. They are on every response once the request passed the limits, errors included.

HeaderDescription
X-RateLimit-LimitThe bucket’s limit
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetSeconds until the current window ends
X-RateLimit-BucketThe bucket’s name

Over a limit, the API answers 429 rate_limited with Retry-After. Nothing is created and no Idempotency-Key is bound.

MethodPathScopePurpose
GET/shopshop:readThe store and key the request authenticates as
GET/labelslabels:readList, look up and sync labels
GET/labels/{label_id}labels:readOne label
GET/labels/{label_id}/documentlabels:printThe label PDF
GET/orders/{order_id}/label-documentlabels:printThe order’s current outbound labels as one PDF
GET/label-documents?label_ids=…labels:printUp to 50 labels as one PDF
POST/labels/{label_id}/printedlabels:printCount a print and apply the print tag
POST/labelslabels:writeCreate a label
GET/label-creationslabels:writeList label creations
GET/label-creations/{label_creation_id}labels:writeOne label creation
POST/label-creations/{label_creation_id}/resolvelabel_creations:resolveResolve a creation in needs_attention
GET/carrier-accountscarriers:readCarrier accounts, services and options
GET/carrier-accounts/{carrier_account_id}carriers:readOne carrier account
GET/orders/{order_id}orders:readThe order as Globe sees it: pickup point, reminders, delivery, COD, labels
PUT/orders/{order_id}/pickup-pointpickup_points:assignSet or change the order’s pickup point
GET/orders/{order_id}/pickup-pointspickup_points:readThe nearest pickup points for the order

IDs carry a prefix: lbl_ (label), lcr_ (label creation), ca_ (carrier account), ak_ (API key). An ID of another store answers 404, exactly like one that does not exist. Order and fulfillment order IDs accept the numeric Shopify ID or the full GID.


One label is one shipment booked at a carrier, created from the Globe admin, from Shopify Flow or through the API. The label object never contains the recipient’s name, address or phone number. Those exist only in the PDF.

FieldDescription
idlbl_…
order{id, legacy_id, name}: the Shopify order GID, numeric ID and name
fulfillment_orders[{id, legacy_id}]: the fulfillment orders the label covers. Empty for whole-order labels
directionoutbound or return
kindshipment, claim (Packeta customer return) or collection (DPD pickup). Claims and collections have no document
statuspending (the carrier has not assigned the shipment number yet, e.g. PPL), ready or failed
failure_reasonFor failed: carrier_import_rejected (PPL refused the shipment at import, after it accepted the batch) or not_finalized
current, supersedes, superseded_bySee below
current_setok or ambiguous. The same value on every label of the order and direction
carrier{code, name, account_id}. account_id is the ca_… ID that GET /carrier-accounts lists
service{code, name}: the product code the carrier received. Only on labels created through the API
sourceadmin, flow or api. null on older labels
cod{amount, currency, source}: what the courier collects, in the currency the carrier received. source says how Globe decided the amount (see Cash on delivery). null when the label did not record it
declared_value{amount, currency}: the value the carrier received. null on admin and Flow labels and where the carrier gets no declared value (see Declared value)
tracking_number, tracking_urlTracking of the shipment
parcels[{tracking_number, tracking_url, weight_grams}]. Always one parcel in v1
batch_idThe internal batch the label was created in
documentSee Label documents
extrasCarrier-specific values, e.g. Packeta’s consign_password. {} for other carriers
created_atWhen the label record was inserted, to the second
updated_atThe last change to the label’s state (export, PPL batch completion, mark printed). null on labels from before this field existed

Current and superseded labels. Globe computes these per order and direction. A label is current while at least one of its fulfillment orders is not covered by a newer label. An older label covering the same fulfillment orders is superseded: current: false, and superseded_by lists the newer labels. A superseded label may still be a valid, paid shipment at the carrier. Failed labels and claims are never current.

current_set: "ambiguous" means two current labels share a fulfillment order, for example a label for two fulfillment orders and a newer label for only one of them. Do not print such a set automatically. Let a person choose.

GET /labels serves two uses: looking up the labels of an order, and keeping a copy of all labels in sync.

Terminal window
curl "https://api-globe.appfleece.app/v1/labels?order_name=1001&current=true&direction=outbound" \
-H "Authorization: Bearer $GLOBE_API_KEY"
{
"data": [
{
"id": "lbl_6ad5df0ce4b0a1f3d2c4b5a6",
"order": { "id": "gid://shopify/Order/5123456789", "legacy_id": 5123456789, "name": "#1001" },
"direction": "outbound",
"status": "ready",
"current": true,
"current_set": "ok",
"tracking_number": "Z1234567890",
"document": {
"availability": "available",
"source": "stored",
"formats": ["label", "a4"],
"available_until": "2026-11-18T09:12:44.000Z",
"url": "https://api-globe.appfleece.app/v1/labels/lbl_6ad5df0ce4b0a1f3d2c4b5a6/document"
}
}
],
"next_cursor": null,
"has_more": false
}

The label is shortened here. Every label carries all fields of the table above.

ParameterDescription
order_idNumeric order ID or GID. Up to 50 values, comma-separated
order_nameExact order name. The # is optional: 1001 and #1001 find the same labels
batch_idThe batch the labels were created in
tracking_numberExact tracking number. Older labels that do not store the number at the top level are not found
directionoutbound or return
currenttrue or false
statuspending, ready or failed
created_after, created_beforeISO 8601, inclusive, second precision
updated_afterLabels whose state changed at or after this time. Inclusive
sort-created_at (default, newest first) or created_at (the sync feed)
cursornext_cursor from the previous page, unchanged
limit1–250, default 50

Pagination. Lists return {data, next_cursor, has_more} without a total. Pass next_cursor as cursor to get the next page. With the direction, status or current filter, a page can hold fewer than limit labels while has_more is true. Keep following next_cursor.

Sync feed. sort=created_at without order_id, order_name, batch_id or tracking_number is the sync feed:

  • It pages oldest first. Labels younger than 15 seconds are held back, so a label created on another server in the same second is not skipped.
  • next_cursor is always set, also on the last page. Save it and ask again in 30–60 seconds.
  • The feed is at-least-once. Deduplicate by id.

Changes after creation. A label’s created_at never changes, so the sync feed does not show a later change, such as a PPL label going from pending to ready. Poll with updated_after to catch those. It works with either sort order.

Label documents are available for 60 days after the label was created. This applies to labels from every source.

  • document.available_until shows the date.
  • After 60 days, document.availability is expired, the document endpoints answer 410 document_expired, and the label cannot be marked printed.
  • The label’s metadata stays readable through GET /labels.
  • An expired label still counts when you create a label for the same fulfillment order. See Existing labels.

Terminal window
curl "https://api-globe.appfleece.app/v1/labels/lbl_6ad5df0ce4b0a1f3d2c4b5a6/document?format=label" \
-H "Authorization: Bearer $GLOBE_API_KEY" \
-o label.pdf

A successful response is application/pdf. An error is the usual JSON error body, so check the status code before you send the file to a printer.

Formats. format=label (default) is the label-printer format. It is never an A4 sheet, even when the carrier account prints A4 in the Globe admin. format=a4 places the label on an A4 page. document.formats lists the formats a label accepts. zpl is reserved and answers 422 format_not_supported.

Carrierformat=label
Most carriersA6
MyGLSThe stored file, in the account’s printer type: Connect (A6) or Thermo
BringLABEL: the label as Bring sends it, 10.2 × 19.2 cm or 10 × 15 cm
PostiLABEL: the label in the size set in Posti
GLS Polandroll: 101 × 160 mm

A label has one page. DPD HU SWAP shipments and Matkahuolto International Home Parcels have two.

Response headerDescription
Content-Dispositionattachment; filename="globe-<order name>-<label id>.pdf"
Globe-Label-Sourcestored (a copy saved at creation) or carrier (rendered by the carrier now)
Globe-Label-FormatThe carrier’s print format that was used

Stored and rendered documents. Labels created through the API, MyGLS and DPD HU labels, and carriers that return the PDF with the shipment have a stored copy. Globe serves it directly. Other labels are rendered at the carrier on demand, which takes a few seconds and has its own rate limit. Globe renders only where the carrier’s print call has no side effect. A label without a stored copy at DPD HU, DPD EasyShip or Pošta bez hranic answers 410 label_not_reissuable.

Excluded carriers. The API never serves documents of Magyar Posta (printing closes the shipment manifest at the carrier), DPD SK, DPD LV, DPD LT, DPD EE and UPS (the label is an image, not a PDF). The document endpoints answer 422 document_unavailable with reason: carrier_excluded. Print these labels in the Globe admin.

Availability. document.availability tells you in advance what the document endpoint will answer:

ValueMeaning
availableThe document can be downloaded now, from the stored copy or by a render
pendingThe label or its PDF is not finished. The endpoint answers 409 label_pending or 409 document_pending with Retry-After
expiredOlder than 60 days
not_applicableA claim, a DPD pickup, or a failed label
not_isolatedAn older DPD HU label whose stored file may contain other labels of its batch
carrier_excludedOne of the excluded carriers above
not_reissuableNo stored copy, and the carrier cannot render it without a side effect

Never create a label again because its document is pending. Retry the download after Retry-After.

Merged documents.

  • GET /orders/{order_id}/label-document returns the order’s current outbound labels as one PDF, oldest first. Return labels are never included. If the current set is ambiguous, it answers 409 ambiguous_current_set with the conflicting labels. An order without a current outbound label answers 404.
  • GET /label-documents?label_ids=lbl_…,lbl_… returns up to 50 labels as one PDF, in the order given.
  • Both are all or nothing. One expired, pending or unavailable label fails the request with that label’s error.

One-click print. For a packing station, either download GET /orders/{order_id}/label-document, or list GET /labels?order_id=…&current=true&direction=outbound and download each label whose document.availability is available. A reprint is the same call again.

Downloading a document does not count as a print. POST /labels/{label_id}/printed counts a print on the label and adds the carrier account’s print tag to the order, as printing in the Globe admin does. The response is the label.

  • It needs an Idempotency-Key: the header, or the idempotency_key query parameter for clients that cannot vary a header. A repeat with the same key within 24 hours replays the first answer and counts nothing.
  • While the first request with a key is still running, a repeat gets 409 idempotency_conflict with state: in_flight, retry: later and Retry-After: 2. Send it again after that to get the first answer.
  • A client that cannot generate keys can send Idempotency-Key: auto. Globe derives the key from the request; an identical request within 60 seconds gets 409 duplicate_request.
  • A label older than 60 days answers 410 document_expired.

POST /labels creates a label for one order. One call books at most one shipment at the carrier and creates at most one label.

The answer is a label creation (lcr_…). It records the decision (carrier, service, COD), the progress and the result. A worker calls the carrier. The API never does.

Try a request with dry_run first. It runs the checks and creates nothing:

Terminal window
curl -X POST https://api-globe.appfleece.app/v1/labels \
-H "Authorization: Bearer $GLOBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"order_id": 5123456789, "dry_run": true}'

Then send it live with an Idempotency-Key:

Terminal window
curl -X POST https://api-globe.appfleece.app/v1/labels \
-H "Authorization: Bearer $GLOBE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: label-5123456789" \
-H "Prefer: wait=20" \
-d '{"order_id": 5123456789}'

A 201 response, shortened:

{
"id": "lcr_6ad5df09e4b0a1f3d2c4b5b1",
"status": "succeeded",
"phase": null,
"next_action": "fetch_document",
"created": true,
"dry_run": false,
"order": { "id": "gid://shopify/Order/5123456789", "legacy_id": 5123456789, "name": "#1001" },
"resolved": {
"selection": "auto",
"matched_rule": "shipping_line_mapping",
"carrier_account_id": "ca_6a1e8d80e4b0a1f3d2c4a001",
"service_code": "1",
"cod": {
"decided": { "amount": "1290.50", "currency": "CZK", "source": "payment_gateway" },
"to_carrier": { "amount": "1291.00", "currency": "CZK", "state": "sent", "adjustments": ["rounded_czk_whole"] }
}
},
"labels": [{ "id": "lbl_6ad5df0ce4b0a1f3d2c4b5a6", "status": "ready", "document": { "availability": "available" } }],
"side_effects": { "fulfillment": { "mode": "fulfill_and_notify", "status": "pending" }, "order_tags": { "status": "pending" } },
"warnings": [{ "code": "cod_adjusted" }],
"error": null,
"attention": null,
"url": "https://api-globe.appfleece.app/v1/label-creations/lcr_6ad5df09e4b0a1f3d2c4b5b1"
}
HeaderDescription
Idempotency-KeyRequired, 8–255 characters, header only. auto is not accepted. Ignored with dry_run
Preferwait=N, 0–60 seconds, default 20. How long the API holds the response for the result
Content-Typeapplication/json

The body is a closed schema. An unknown field is 422 validation_error, so a typo in a field that costs money never falls back to a default.

FieldDefaultDescription
order_id or order_name–Exactly one. order_id is the numeric ID or GID. order_name matches exactly, # optional, case-insensitive
fulfillment_order_idsall shippableAn array with exactly one fulfillment order ID, numeric or GID. The label is for that fulfillment order
all_locationsfalseWithout fulfillment_order_ids: one label for the shippable fulfillment orders of every location
carrier_account_idchosen by rulesca_… from GET /carrier-accounts
service_codechosen by rulesA service code of the account. Requires carrier_account_id
parcelsderived[{"weight_grams": 1200}]: exactly one parcel, 1–1,000,000 g
codderived{"amount": "1290.50", "currency": "CZK"}. 0 to 9,999,999.99, at most two decimals. "0" ships without COD
declared_valuederivedSame shape, range and currency rule as cod. Only for some carriers, see Declared value
carrier_optionsaccount defaultsOnly keys the account lists in options
fulfillmentaccount_defaultaccount_default, none, fulfill or fulfill_and_notify
on_existingreturnreturn, reject or create_new. See Existing labels
replaces–Required with create_new: the label (lbl_…) and creation (lcr_…) IDs that block the target today. [] when nothing blocks
include[]["document"] returns the PDF in the response
client_referencenullYour reference, up to 64 characters. Stored and returned, never sent to the carrier
dry_runfalseRun the checks, create nothing

The recipient, address, phone, email, pickup point and sender always come from the order and the carrier account. To change them, change the order.

v1 creates outbound shipments with one parcel. It does not create returns, multi-parcel shipments, or cancel shipments.

The key protects against booking a shipment twice when a request is repeated. It binds to the label creation for 30 days.

Repeat with the same keyResult
The creation is still runningJoins it and waits. The carrier is never called twice
succeededThe original answer (201 or 200) with Idempotency-Replayed: true. With include, the PDF is served again from storage
needs_attention202 with the same creation. Never a new attempt
abandoned409 label_exists with reason: shipment_outside_globe
failedA new attempt with a new lcr_… ID. The body may differ
A different body409 idempotency_conflict
  • A request refused before the creation record exists (authentication, validation, rate limit) binds nothing.
  • The body is compared after normalization: IDs as GIDs, order_name without # and lowercase, defaults filled in, amounts with two decimals. Prefer is not part of it.
  • A key derived from the order, such as label-5123456789, works well. A failed attempt releases it, so the same key can go again after you fix the order. A replacement label for the same order needs a new key.

If a POST /labels gets no answer, or a 5xx without Globe’s error body (such as a 502 or 504 from the proxy), send the same request again with the same key.

"dry_run": true runs everything up to the carrier call: the order, the target fulfillment orders, existing labels, carrier selection, COD and the checks Globe runs before it calls a carrier. It creates no record, binds no key, takes no lock and calls no carrier.

The answer is 200 with status: validated, id: null, the full resolved block and warnings, or the error a live call would get. would says what a live call would do: create, return_existing or wait_for_existing. resolved.cod.to_carrier.state is predicted.

A dry run cannot predict a carrier refusal, a carrier outage, a change to the order before the live call, or a concurrent creation. It needs labels:write and the store’s write access, and has its own rate limit. include is not allowed with it.

OutcomeStatusHeadersBody
New label201Location (the label), Content-Location (the creation)succeeded, created: true, one label
Existing labels returned (on_existing: "return")200Content-Locationsucceeded, created: false, the existing labels
Dry run200–validated
Not finished within the wait202Location (the creation), Retry-After: 2processing, next_action: poll
Outcome unknown202Locationneeds_attention, next_action: manual_check
Nothing created4xx, 503Retry-After where it appliesError body

Successful responses carry Preference-Applied: wait=N, the wait that was applied. A 202 means: do not create the label again. Poll GET /label-creations/{id}, which also accepts Prefer: wait=N and answers as soon as the creation leaves processing. You can also wait for the label_creation.updated webhook.

Decide on next_action, not on the status code:

next_actionWhat to do
fetch_documentDownload the labels whose document.availability is available
wait_for_documentA document is pending. Retry the download after Retry-After
pollThe creation is running. Poll it, never create it again
manual_checkA person has to check the carrier. See needs_attention and resolve
fix_and_retryFix the cause in error, then send the request again
retry_laterSend the request again after Retry-After
noneNothing to do. The reason is in warnings or error
statusMeaning
processingThe creation is running. phase: queued, preparing, waiting_for_lock, sending_to_carrier, waiting_for_carrier, finalizing
succeededEvery label in labels is ready and has its final tracking number
failedNo shipment exists. error holds the code, and the Idempotency-Key is free again
needs_attentionGlobe does not know whether the shipment exists, or it exists without a usable label. attention has the details
abandonedThe shipment exists at the carrier and is handled outside Globe
validatedDry run only. Never stored
  • created is true when this attempt created the shipment, false when it provably did not, and null while unknown.
  • resolved is filled in as the creation runs. It is complete from sending_to_carrier on.
  • A creation that has not reached the carrier 5 minutes after it was created is never sent: it fails with not_started.
  • A creation that reached the carrier leaves processing within about 10 minutes.
  • GET /label-creations lists creations newest first. Filters: order_id, order_name, status, idempotency_key, client_reference, created_after, updated_after. An ERP that polls can send updated_after to collect changes.

Before it calls a carrier, Globe checks the target fulfillment orders for existing labels. Current outbound labels block, whatever their age, carrier or source (admin, Flow or API). Superseded labels do not block. on_existing decides what happens:

Situationreturn (default)reject
A creation in needs_attention covers the target409 unresolved_creation409 unresolved_creation
Another creation, or an export from the admin or Flow, is running for the targetWaits for it (phase: waiting_for_lock), then decides again409 creation_in_progress
An abandoned creation covers the target409 label_exists (shipment_outside_globe)same
No label covers the targetCreates the labelCreates the label
Ready labels cover the whole target200 with the existing labels, created: false409 label_exists (existing_label_ready)
A covering label is pending, for less than 10 minutesAdopts it and finishes when it is ready (at most 5 minutes). If it fails instead, Globe decides again409 label_exists (existing_label_pending)
Partial coverage, an ambiguous set, an expired label, a label on a fulfillment order replaced by an order edit, a pending label older than 10 minutes, or an older label without per-fulfillment-order coverage409 label_exists with the matching reasonsame

create_new creates a new label when replaces lists exactly what blocks the target today. Otherwise it answers 409 precondition_failed with details.current_blocking. It never goes past an unresolved or running creation (unresolved_creation, creation_in_progress), or a label pending for less than 10 minutes (label_exists, existing_label_pending). A store can create 50 labels a day with create_new. The replaced label stays a valid, paid shipment at the carrier; v1 cannot cancel it.

return and explicit values. When return would hand back an existing label, the request’s carrier_account_id, service_code, cod, declared_value and parcels must match it. Amounts are compared after the carrier’s rounding. service_code is compared as a catalogue code: PPL AUTO or SMAR|SMAD matches the product the carrier got for that order. A difference answers 409 label_exists (existing_label_differs) with details.differences. If the label does not record the value, or several labels cover the target, the answer is existing_label_unverifiable. A request that differs only in carrier_options or fulfillment gets the existing label and the warning request_parameters_not_applied. A returned label never triggers fulfillment.

A creation enters needs_attention when Globe cannot tell whether the carrier created the shipment, or when the shipment exists but Globe did not get a usable label. Globe sends the carrier one create request per creation and never repeats it, even for carriers where an export from the Globe admin retries after an error.

attention fieldDescription
reasoncarrier_timeout, carrier_error, worker_lost (shipment unknown); label_not_retrieved, confirmation_missing (shipment exists)
shipment_at_carrierunknown or exists
carrierThe carrier
carrier_referenceThe reference to look for in the carrier’s portal: the Packeta packet ID, the PPL batch ID, the MyGLS parcel ID or the DPD CZ parcel number. Set once the carrier accepted the shipment. null for other carriers
carrier_notedraft_until_label_printed for DPD CZ after an unclear create call: the shipment may exist only as an unprinted draft. Otherwise null
sent_atWhen Globe called the carrier
resolve_allowed_atThe earliest time not_created is accepted

Packeta, PPL, MyGLS and DPD CZ record the carrier’s acceptance before Globe fetches the label. A creation that stops after the acceptance is needs_attention with shipment_at_carrier: exists and the reference, never unknown. An acceptance that arrives after the creation entered needs_attention updates attention the same way, and not_created is then refused.

While a creation is in needs_attention:

  • Its fulfillment orders are locked. The Globe admin and Flow cannot export them, and a new POST /labels for them gets 409 unresolved_creation in every mode.
  • Globe keeps trying to get the label for 24 hours. If it succeeds, the creation becomes succeeded on its own.

A person checks the carrier’s portal and resolves the creation with POST /label-creations/{id}/resolve. It needs the label_creations:resolve scope (see permissions) and no Idempotency-Key.

{ "outcome": "not_created", "tracking_number": null, "note": "Not in the carrier portal" }
outcomeResult
not_createdThe shipment does not exist. The creation becomes failed with error.code: resolved_not_created, and the lock and the key are released. A new POST /labels creates the label. Allowed only while shipment_at_carrier is unknown, and not before resolve_allowed_at (15 minutes after sent_at); earlier gets 409 resolve_too_early
shipment_existsThe shipment exists and is handled outside Globe. The creation becomes abandoned and the lock is released. A pending label of the creation becomes failed (not_finalized)

tracking_number and note (up to 200 characters) are optional. Repeating the same outcome answers 200. A different outcome afterwards gets 409 already_resolved, and a creation that is not in needs_attention gets 409 not_resolvable.

Unresolved after 24 hours. A creation still in needs_attention 24 hours after it entered that state becomes abandoned automatically. Its lock is released, so the Globe admin and Flow can print for the order again. Its key stays bound, so a repeat answers 409 label_exists (shipment_outside_globe). For a new label through the API, send on_existing: "create_new" with the creation’s lcr_… ID in replaces. A resolve within the 24 hours takes precedence. Globe sends label_creation.updated for the change.

An abandoned creation blocks its fulfillment orders for new API labels until its record is deleted, 90 days after it was created.

Every label creation decides COD with the same rule as the Globe admin and Flow. The first match wins:

OrderSourcesource value
1cod in the requestrequest
2The order metafield globe/cod_value. 0 means no COD, even with a COD payment methodorder_metafield
3A COD payment gateway on the order, such as “Cash on delivery”, “Dobírka” or “Nachnahme”. The amount is the order’s outstanding balancepayment_gateway
4The store’s COD rule for orders without any payment gateway, such as draft orders. Off by defaultshop_rule
5Nonenone
  • Currency. The label currency is the globe/currency metafield, otherwise the order currency. Globe never converts amounts. An explicit cod or declared_value must be in the currency the carrier receives, otherwise 422 currency_mismatch.
  • Labels for one fulfillment order. An automatic amount is split across the order’s parcels by the value of the goods in each, after discounts. resolved.cod.derivation.split shows the split. An explicit cod is never split.
  • Invalid metafield. An invalid globe/cod_value without an explicit cod fails with 422 label_validation_failed (cod_metafield_invalid). It never reads as zero.
  • No COD service. If the service cannot collect COD, a cod above zero fails with cod_not_supported. Send "0" to ship without it.

The creation reports COD in these fields:

FieldDescription
requested.codEcho of the request’s cod. In every response, including an early 202
resolved.cod.decidedWhat Globe decided: amount, currency, source
resolved.cod.to_carrierWhat the carrier receives after its own adjustments: amount, currency, adjustments, and state (predicted in a dry run, sent once the worker sent it)
resolved.cod.derivationHow the automatic amount was computed: the base, the raw metafield, the matched gateway, the outstanding balance, the label’s share and the split

to_carrier differs from decided when the carrier rounds. Packeta rounds CZK to whole crowns and HUF up to a multiple of 20. Boxpi rounds CZK and HUF to whole units, Pošta bez hranic CZK to whole crowns, Foxpost every currency to whole units. GET /carrier-accounts lists this per carrier in carrier.cod.rounding_by_currency. The warning cod_adjusted marks the difference.

Packeta converted metafields. The order metafields custom.converted_value and custom.converted_currency replace an automatic COD (from a gateway or the store rule) with the converted amount, scaled to the label’s share of the order. custom.packet_value sets the declared value in that currency. An explicit cod and globe/cod_value win over the conversion, with the warning cod_conversion_metafield_ignored. If the metafields would send the COD in a currency other than the packet’s, the creation fails with cod_packet_currency_mismatch. A custom.converted_value that is zero or not a number fails with cod_metafield_invalid.

On the created label, cod holds the to_carrier amount and currency together with the decided source.

resolved.declared_value has decided (with source: request or order) and to_carrier, like COD.

  • An explicit declared_value is accepted only where GET /carrier-accounts says declared_value.supported: true. In v1 that is Packeta. Elsewhere the request fails with 422 unsupported_parameter.
  • MyGLS, DPD CZ and PPL never get a declared value. Their resolved.declared_value.to_carrier is null.
  • On the created label, declared_value holds the to_carrier amount and currency.

The target of a label is the order’s shippable fulfillment orders: open or in progress, with a physical delivery method.

  • On a split order or a ship & pickup order, in-store pickup, local delivery and retail fulfillment orders are never a label target while the order has an open parcel fulfillment order. Without fulfillment_order_ids, the label covers the parcel fulfillment orders only. Naming a pickup or local fulfillment order fails with 422 order_not_eligible (fulfillment_order_not_parcel). Once the parcel has a label and only the pickup or local delivery part is left, a request without fulfillment_order_ids fails the same way instead of sending those goods by courier. An order that has only local delivery or pickup fulfillment orders and no label yet still gets a courier label.
  • The whole order’s COD rides with the parcels. Pickup and local delivery fulfillment orders take no share of it.
  • Carrier selection uses the shipping line of the parcel.
  • When no parcel fulfillment order is open, local delivery and pickup fulfillment orders can get a label, as in the Globe admin.
  • An order whose fulfillment orders all have no delivery method (digital lines, or an order imported without shipping) gets one label for the whole order. Leave out fulfillment_order_ids.
  • An order with shippable fulfillment orders at more than one location needs fulfillment_order_ids or all_locations: true. Otherwise it fails with 422 fulfillment_order_required, which lists the fulfillment orders and their locations.
  • Orders with more than 20 fulfillment orders fail with too_many_fulfillment_orders. Use the Globe admin for them.

GET /carrier-accounts lists what POST /labels can use. It never returns credentials or the sender address. The list is not paginated.

FieldDescription
idca_…, the value for carrier_account_id
nameThe name the store gave the account
carrier{code, name, cod: {rounding_by_currency}}
api_creationenabled, or not_enabled when label creation through the API is switched off for the account
services[{code, name, delivery, requires_pickup_point, creatable, document, cod: {supported}, declared_value: {supported}}]. code is a valid service_code. creatable: false marks return products. document is stored, stored_when_available (Packeta through an external carrier: the PDF arrives later) or carrier_excluded (print in the Globe admin)
options[{key, type, default, enum}]: the keys carrier_options accepts and the default applied without them
defaults{fulfillment, fulfillment_timing, order_tags} the account applies
capabilities{completion, cancel}. completion is sync, or deferred when the carrier accepts the shipment now and completes it later. For PPL the creation stays processing (phase finalizing) until the PPL batch completes, which can take longer than Prefer: wait, so poll it. For Boxpi the label can exist before Boxpi assigns its tracking number. cancel is always false

Selection:

  • With carrier_account_id and service_code, Globe uses them.
  • With carrier_account_id only, the service comes from the account’s shipping method mapping and custom rules, or from the external carrier of the order’s Packeta pickup point.
  • With neither, Globe applies the same rules as the Flow action: the external carrier of a Packeta pickup point, the account serving the pickup point’s network, the shipping method mapping, then custom rules. Accounts with api_creation: not_enabled are skipped.
  • No match, more than one matching account, or an account without a service fails with 422 carrier_selection_failed and a reason.

resolved.selection is explicit or auto, and resolved.matched_rule names the rule. resolved.service_code is the catalog service; resolved.carrier_product_code is what the carrier actually receives. They differ for PPL, where AUTO and pairs like SMAR|SMAD resolve per shipment.

Fulfillment and order tags run after the label is ready, never before. They do not change the creation’s outcome.

fulfillmentEffect
account_defaultWhat the carrier account is set to do. On accounts that fulfill when the carrier takes over the parcel, the status is deferred
noneNo fulfillment
fulfillFulfill the order in Shopify now
fulfill_and_notifyFulfill now and send the customer Shopify’s shipping email

An explicit value runs immediately, also on accounts set to fulfill at carrier handover.

side_effects.fulfillment ({mode, status, reason}) and side_effects.order_tags ({status}) report the progress. status is pending, done, deferred, skipped or failed. Globe retries a failed fulfillment for 10 minutes. If it still fails, the status is failed and the warning fulfillment_failed is added; the label stays valid. create_new on a fulfillment order that is already fulfilled skips the fulfillment with the warning tracking_not_updated: Shopify keeps the old tracking number.

The shipping_label.created webhook and the label email go out for API labels as for any label, with the stored PDF in label format.

Automatic batch steps at the carrier do not run for API labels, because the API creates one label per call: the GLS Poland pickup confirmation, the DPD Portugal end-of-day close and the Toptrans auto send. Do them in the carrier’s portal or with a Globe admin export. A Toptrans order stays a draft until it is sent; its label prints either way.

"include": ["document"] adds the PDF to labels[].document as content (base64), content_type, format and size_bytes. It needs the labels:print scope and counts against the document rate limit.

  • Only 200 and 201 carry content. A 202 never does.
  • Only stored copies are included. A label rendered on demand gets content: null and the warning document_not_stored; download it with GET /labels/{id}/document.
  • A pending document gets content: null and the warning document_pending.
  • A document that cannot be served gets content: null and the warning document_unavailable.
  • PDFs over 2 MB get content: null and the warning document_too_large.

Warnings never change the outcome. Each has a code, and can have a message and details.

CodeMeaning
cod_adjusted, declared_value_adjustedThe carrier receives a different amount or currency than Globe decided (rounding, conversion)
cod_overrides_order_metafieldThe request’s cod replaced globe/cod_value
cod_differs_from_derivedThe request’s cod differs from the amount Globe would derive for the label
cod_metafield_invalid_ignoredAn invalid globe/cod_value was ignored because the request has cod, or an invalid globe/currency was ignored and the order currency used
cod_currency_relabelledThe automatic COD (payment gateway or store rule) is the outstanding amount in the order currency, but it goes to the carrier in the globe/currency currency, unconverted
cod_conversion_metafield_ignoredPacketa’s converted COD metafields were ignored for an explicit amount
cod_full_amount_on_partially_shipped_orderA whole-order label carries the full COD although part of the order already shipped
cod_selection_differs_from_order_codThe COD of the labels differs from the order’s COD
cod_on_paid_orderThe label carries COD, but the order is paid
cod_differs_from_existing_labelA returned existing label records a different COD than Globe derives for the order today. Only when the request has no cod; with cod, a difference is 409 label_exists (existing_label_differs). details: label_id, and existing and derived_now as {amount, currency}
existing_label_cod_not_recordedA returned existing label is older than the COD record, so its COD cannot be compared. details.label_id names it
cod_differs_from_replaced_labelcreate_new: a replaced label recorded a different COD than the new label gets
request_parameters_not_appliedAn existing label was returned; carrier_options and fulfillment apply only to a new label
document_pending, document_unavailable, document_not_stored, document_too_largeSee PDF in the response
fulfillment_failedFulfillment in Shopify failed
tracking_not_updatedThe fulfillment order was already fulfilled; Shopify keeps the old tracking number
missing_weightNo weight was found for the parcel
missing_phoneThe recipient has no phone number

GET /orders/{order_id} returns an order as Globe sees it. It is read live from Shopify, so it always matches the admin. It never contains the customer’s name, address, phone number or e-mail.

{
"id": "gid://shopify/Order/5530000001",
"legacy_id": 5530000001,
"name": "#1001",
"created_at": "2026-10-19T10:00:00.000Z",
"cancelled": false,
"fulfillment_status": "UNFULFILLED",
"financial_status": "PENDING",
"pickup_point": {
"required": true,
"selected": {
"id": "12345",
"carrier": "packeta",
"carrier_name": "Packeta",
"name": "Z-BOX Praha 1, Karlova",
"type": "zbox",
"address": { "street": "Karlova", "street_number": "3", "city": "Praha", "postal_code": "11000", "country": "CZ" },
"formatted_address": "Karlova 3, 11000 Praha",
"latitude": 50.0861,
"longitude": 14.4151,
"distance_km": null,
"url": null
},
"selected_at": "2026-10-19T10:05:00.000Z"
},
"reminder_emails": [
{ "type": "pickup_point_missing", "status": "sent", "at": "2026-10-19T12:00:00.000Z", "skip_reason": null }
],
"delivery": [
{
"fulfillment_id": "gid://shopify/Fulfillment/4410000001",
"tracking_number": "Z1234567890",
"carrier": "packeta",
"status": "IN_TRANSIT",
"carrier_status_code": "4",
"delivery_date": null,
"updated_at": "2026-10-20T07:00:00.000Z"
}
],
"cod": { "is_cod": true, "paid": false },
"label_ids": ["lbl_66f0a1b2c3d4e5f60718293a"]
}
FieldDescription
pickup_point.requiredThe order’s shipping method is a pickup point method of one of your carriers
pickup_point.selectedThe point saved on the order, or null
reminder_emailsThe pickup point reminder e-mails Globe sent or skipped (skip_reason), oldest first. Never says to whom
deliveryThe latest status Globe has from the carrier, one entry per fulfillment and tracking number
cod.paidFor a cash on delivery order, true once the money was collected. null for other orders
label_idsThe order’s labels, oldest first. Read them with GET /labels/{label_id}

PUT /orders/{order_id}/pickup-point sets or changes the order’s pickup point. It does what Edit pickup point does in the admin: it saves the point on the order, applies the carrier’s tags, attributes and order note, changes the shipping address to the point’s when the carrier’s settings say so, and sends the pickup_point.selected webhook. The response is the finished order.

Terminal window
curl -X PUT https://api-globe.appfleece.app/v1/orders/5530000001/pickup-point \
-H "Authorization: Bearer $GLOBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"carrier": "packeta", "pickup_point_id": "12345"}'

The request is refused when:

  • the order is cancelled or fulfilled, or its shipping method is not a pickup point method (422 order_not_eligible);
  • the order already has a label (409 label_exists) or a label creation is running (409 creation_in_progress) — a label is made for one pickup point;
  • the point does not exist, belongs to a carrier the order’s shipping method does not map to, is a point type the shipping method does not offer, or needs a customer ID (DHL Packstation, PPL ParcelBox in Germany) (422 pickup_point_not_available).

Carriers whose points Globe reads live from the carrier (DHL, GLS, UPS and others) accept a point among the 50 nearest to the order’s shipping address (GET /orders/{order_id}/pickup-points). Sending the point the order already has answers 200 and changes nothing, so a retry is safe without an Idempotency-Key. The store needs write access, like for creating labels.

GET /orders/{order_id}/pickup-points returns the nearest points of the carriers the order’s shipping method maps to, near the order’s shipping address, nearest first, with distance_km. It is the same search the reminder e-mail uses, so the first point is the one the e-mail would offer. The address itself is never returned.

Add carrier=packeta for one carrier and limit (1–25, default 10). Points that need a customer ID are left out. An order without a pickup point shipping method returns an empty list. An address that cannot be located answers 422 validation_error with details.reason: address_not_found.

The API finds pickup points for orders only. There is no search by place.

{
"data": [
{
"id": "12345",
"carrier": "packeta",
"carrier_name": "Packeta",
"name": "Z-BOX Praha 1, Karlova",
"type": "zbox",
"address": { "street": "Karlova", "street_number": "3", "city": "Praha", "postal_code": "11000", "country": "CZ" },
"formatted_address": "Karlova 3, 11000 Praha",
"latitude": 50.0861,
"longitude": 14.4151,
"distance_km": 0.31,
"url": null
}
],
"next_cursor": null,
"has_more": false
}

Pass a point’s carrier and id to PUT /orders/{order_id}/pickup-point.

Two webhook topics complement the API. See Webhooks for setup and signatures.

  • shipping_label.created fires for every new label, whatever created it. Labels created through the API also carry labelCreationId and clientReference.
  • label_creation.updated fires when a label creation changes state. It never carries a PDF.

Webhook delivery is at-least-once. The current state is always readable through the API.

https://api-globe.appfleece.app/v1/openapi.json is generated from the same registry that routes requests, so it lists every endpoint, parameter, schema and error code of the live API.