1. Updates
PostPlus API
  • Authentication, Environments
  • Endpoints Overview
    • Parcels Endpoints
    • Shipments Endpoints
    • Tracking Endpoints
    • Accounts Endpoints
  • Scenarios And Workflows
    • Working with parcels
    • Create or update parcel record
    • Cancel or delete a parcel record
    • Manifesting parcels in bags and shipments
    • Query parcel tracking events
    • Import parcel tracking events
  • Updates
    • [2026-09-15] EU product identifiers
  • All API Endpoints
    • Parcels
      • Create or update single parcel.
      • Create or update up to 200 parcels in a single request.
      • Get parcel details by parcel Id.
      • Get up to 100 parcels details by parcel Ids.
      • Get parcel details by parcel number (tracking number).
      • Get up to 100 parcels details by parcel numbers (tracking numbers).
      • Get parcel details by sender reference number.
      • Get up to 100 parcel details by sender reference numbers.
      • Query up to 500 parcels.
      • Delete parcel by Id.
      • Delete up to 100 parcels by Ids.
      • Get print details and contents by print Id.
      • Get up to 100 parcel print details and contents by print Ids.
      • Get pickup point details by Id.
      • Query pickup points.
      • Group parcels into bags and link to a shipment (update parcel references). When AllowPartialSuccess is true, valid parcels are updated and invalid ones returned in FailedParcels.
      • Get parcel details by manifest reference numbers.
      • Get up to 100 parcel details by manifest reference numbers.
      • Get parcel details by carrier reference numbers.
      • Get up to 100 parcel details by carrier reference numbers.
    • Shipments
      • Cancel erroneous parcels in a shipment.
      • Delete shipment manifest file.
      • Create new shipment.
      • Create new bag level shipment.
      • Update bag level shipment.
      • Link parcels with specified bag numbers to a shipment.
      • Validate and prepare shipment for submitting.
      • Submit and lock shipment and it's parcels.
      • Group parcels into bags and link to a shipment, then prepare and submit shipment in one transaction.
      • Delete shipment.
      • Update shipment.
      • Get shipment details by shipment id.
      • Query up to 500 shipments.
      • Upload shipment manifest file.
      • Upload shipment document.
      • Get shipment details by shipment number.
    • Documents
      • Download manifest file.
      • Download shipment documents in archive file.
      • Download shipment document file by Id.
      • Download parcel label by Id.
      • Generate and download generic bag labels.
      • Generate and download bag label.
      • Download resulting (processed) manifest file.
      • Generate and download shipment parcel labels.
      • Generate and download parcel commercial invoices.
      • Download resulting (processed) shipment file.
    • Tracking
      • Fetch up to 500 tracking events in cursor fashion.
      • Get event codes and other metadata.
      • Get tracking events by the list of parcel numbers, up to 50, comma separated.
      • Get tracking events by the list of sender reference numbers, up to 50, comma separated.
      • Get tracking events by the list of parcel numbers or sender reference numbers, up to 50, comma separated.
      • Get bag tracking events by the list of bag numbers, up to 50, comma separated.
      • Get bag tracking events by the list of bag numbers or shipment numbers, up to 50, comma separated.
      • Upload tracking events file.
    • Accounts
      • Get current account details.
    • Integrations
      • Add up to 500 tracking events to the processing queue. The whole batch either succeeds or fails.
      • Add tracking event with generic payload.
  • Shipments
    • Update a shipment document's effective date. The document's visibility and status are preserved.
      PUT
  • HsCodes
    • Resolve HS codes by list of descriptions.
      POST
  • Tracking
    • Get the parcel journey phases, in journey order - the dictionary for the category that event codes and tracking events carry. Changes only on release, so fetch it once and cache it.
      GET
  • Schemas
    • AccountAddressType
    • AccountCommonSettings
    • AccountSettingsAddressInfo
    • AddressInfo
    • AddTrackingEventsRequest
    • BagEventsResponse
    • BagPrintInfo
    • BagPrintType
    • BagStatus
    • BagViewInfo
    • CancelShipmentParcelsWithErrorsRequest
    • ContainerType
    • CreateIntegrationEventsRequest
    • EmaiNotificationsSettings
    • CreateOrUpdateManyParcelsRequest
    • CreateOrUpdateParcelAdditionalInfo
    • IncludePrintSizes
    • CreateOrUpdateParcelIdentifiers
    • LabelSize
    • CreateOrUpdateParcelInfo
    • CreateOrUpdateParcelReceiverInfo
    • CreateOrUpdateParcelReferences
    • CreateOrUpdateParcelRequest
    • CreateOrUpdateParcelSenderInfo
    • CreateOrUpdateParcelStatusInfo
    • CreateOrUpdateSingleParcelRequest
    • CustomsSettings
    • DeleteParcelRequest
    • TaxType
    • DownloadBagPrintRequest
    • DownloadManifestFileRequest
    • DownloadParcelPrintRequest
    • DownloadShipmentDocumentRequest
    • DownloadShipmentDocumentsRequest
    • FileFormat
    • FileStatus
    • GenerateBagPrintsRequest
    • GenerateParcelCommercialInvoicesRequest
    • GenerateParcelCommercialInvoicesResponse
    • ParcelLinkResultInfo
    • ParcelValidationSettings
    • GenerateShipmentParcelPrintsResponse
    • GetAccountDetailsResponse
    • GetCurrentAccountDetailsRequest
    • GetEventsBatchResponse
    • UpdateShipmentDocumentRequest
    • GetManyParcelPrintsResponse
    • EventCategoryInfo
    • LinkBagsToShipmentRequest
    • GetPickupPointDetailsRequest
    • GetPickupPointDetailsResponse
    • CreateBagLevelShipmentRequest
    • CreateShipmentRequest
    • GetShipmentDetailsResponse
    • LabelsSettings
    • LeanMileSettings
    • MailType
    • ResolveHsCodesByDescriptionsRequest
    • ManifestAndSubmitShipmentParcelInfo
    • ManifestAndSubmitShipmentRequest
    • ManifestAndSubmitShipmentResponse
    • ManifestFileType
    • UpdateManyParcelReferencesRequest
    • ManifestFileViewInfo
    • ManyParcelsDetailsResponse
    • BagTrackingEventInfo
    • NewIntegrationEvent
    • NewTrackingEvent
    • ParcelAdditionalInfo
    • ParcelAndTrackingEventInfo
    • EmaiNotificationsInfo
    • ParcelCommercialInvoiceInfo
    • ParcelDetailsResponse
    • ParcelDocument
    • ParcelDocumentType
    • LinkBagsToShipmentResponse
    • ParcelEventsResponse
    • ParcelIdentifiers
    • ParcelInfo
    • ParcelNrSequenceInfo
    • ShipmentDocumentViewInfo
    • ParcelNrType
    • TrackingEventInfo
    • ParcelPrintFormat
    • UpdateManyParcelReferencesResponse
    • ParcelPrintType
    • ParcelReceiverInfo
    • CreateOrUpdateParcelItemInfo
    • ParcelSenderInfo
    • ParcelStatus
    • ParcelStatusInfo
    • ParcelItemInfo
    • ParcelTransactionType
    • PickupPointInfo
    • PickupPointType
    • EventCodeInfo
    • ParcelPrintInfo
    • ParcelReferences
    • PostalLabelSettings
    • PostalSettings
    • PrepareShipmentRequest
    • PrepareShipmentResponse
    • QstepSettings
    • QueryParcelsResponse
    • QueryPickupPointsResponse
    • QueryShipmentsResponse
    • RateManagementSettings
    • SearchBagEventsResponse
    • ResendOrRelabelParcelRequest
    • SearchParcelEventsResponse
    • ShipmentArrivalInfo
    • ShipmentArrivalViewInfo
    • ShipmentDocumentType
    • ShipmentManifestLevel
    • ShipmentManifestSettings
    • ShipmentStatus
    • ShipmentStatusInfo
    • ShipmentTerminalInfo
    • ShipmentType
    • ShipmentViewInfo
    • SubmitShipmentRequest
    • TelemetrySettings
    • TrackingParcelInfo
    • UpdateBagLevelShipmentRequest
    • UpdateShipmentRequest
    • UploadManifestFileResponse
    • UploadShipmentDocumentResponse
    • UploadTrackingEventsFileResponse
    • UpsertBagRequest
    • X7TradeSettings
  1. Updates

[2026-09-15] EU product identifiers

From 1 November 2026, every item on an EU-bound B2C parcel must carry customs product identifiers, under Commission Delegated Regulation (EU) 2026/1022. They are collected per item, so a parcel with three different products carries three sets.
This page tells you what to change in an existing integration, then specifies each field.

Migrating an existing integration#

If you already call create-or-update or create-or-update-many, the whole change is inside parcel.items[]:
1.
Add nsCode, spCode and spCodeNotApplicable to each item. Nothing else in the request structure changes.
2.
Keep sending skuCode as you do today — it is the Merchant PID, unchanged.
3.
Decide per item what spCodeNotApplicable should be. This is the only part that needs a rule rather than a mapping.
4.
Optionally add originCountryCode if your items differ in origin.
5.
Check hasErrors in the response, which echoes every item as we stored it.
The shipment calls need no change — they carry no item-level data. And there is no cutover to coordinate: all four fields stay optional until 1 November, so you can deploy the day you are ready.

Before and after#

The one decision: spCodeNotApplicable#

Does the product carry a manufacturer barcode (GTIN/EAN/UPC/ISBN)?
├── Yes → spCode = the barcode    + spCodeNotApplicable = false
├── No  → spCode = "" (or omit)   + spCodeNotApplicable = true
└── Don't know yet → omit both fields entirely
Never send false with an empty spCode, and never send true alongside a barcode. Both are contradictions and both are returned as parcel errors. Omitting the field is always safe — it records "not stated", which is not the same as false.

The identifiers#

FieldCustoms elementWhat to sendMax length
skuCodeC127 — Merchant PIDYour own product code50
nsCodeC128 — Non-standardised manufacturer PIDThe manufacturer's model or part number50
spCodeC129 — Standardised PIDThe barcode: GTIN-8/12/13/14, EAN, UPC or ISBN30
spCodeNotApplicableY081 — exception codetrue only when the product genuinely carries no barcode—
Each item also takes an optional originCountryCode (ISO 3166-1 alpha-2, e.g. US). It is not one of the identifiers and is not part of the mandate — origin is a separate element we otherwise resolve per shipment/account. Send it when your items differ in origin; omit it otherwise.
📌 Two different fields share the name originCountryCode. The one here is per item, inside parcel.items[]. The shipment request has its own arrivalInfo.originCountryCode — the origin of the transport, unrelated. Setting one does not affect the other.

Timeline#

PeriodBehaviour
Now → 31 Oct 2026All four fields optional. The Commission has stated no sanction applies to missing or incorrect PIDs during this window.
From 1 Nov 2026Mandatory per item on EU-bound B2C parcels. A declaration missing a mandatory PID is incomplete and will not be accepted for release.
There is no soft-enforcement period afterwards. Treat the date as hard.

Field-by-field rules#

skuCode — Merchant PID (C127)#

Your own product code, e.g. CGN-02333. Must be unique per product variant: same brand, size, colour and packaging is one code; two sizes are two codes. Nothing changes in what you already send — only that from 1 November it must be on every item.

nsCode — Non-standardised manufacturer PID (C128)#

The manufacturer's own model or part number, e.g. NOW-0674. Mandatory, with no exception code — there is no nsCodeNotApplicable, and Y081 covers a missing spCode only.
Where the manufacturer assigned no separate reference, DG TAXUD guidance permits repeating the spCode value here — but send it explicitly; we never copy it across for you. The declaration is yours; a value we filled in would be our assertion, not yours.

spCode — Standardised PID (C129)#

The manufacturer's barcode — GTIN-8/12/13/14, EAN, UPC or ISBN — exactly as printed on the product. On receipt:
Grouping spaces are stripped. 590 1234 123457 is stored as 5901234123457; those spaces are typography, not data.
Hyphens are kept. In an ISBN they are part of how the code is printed, and C129 is transmitted as printed.
Never padded, and the check digit is never recomputed or validated. A GTIN-12 stays 12 digits.
Upper-cased, which matters only for an ISBN-10 X check digit.
skuCode and nsCode are free-form references, so they are not upper-cased — whitespace is collapsed and nothing else. If a code would exceed its length limit, dropping a hyphen is the right way to shorten it.

spCodeNotApplicable — exception code Y081#

Send true only when the product genuinely carries no standardised barcode. Customs is then given exception code Y081 in place of C129.
The field has three states, recorded exactly as you send them:
ValueMeaningRequires
omitted / nullNot stated — you have said nothing either waynothing
trueNo barcode; claims the Y081 exemptionspCode empty
falseA barcode existsspCode non-empty
true and false are assertions, so each must agree with spCode. null asserts nothing and is never a contradiction — silence is allowed, a false statement is not.
If you always populate spCode, always sending false is correct. If you cannot guarantee that, omit the field on the items you are unsure about rather than defaulting to false.

originCountryCode — optional, ISO 3166-1 alpha-2#

Two-letter code, e.g. US; case is normalised, so us is accepted. Optional, and it stays optional after 1 November. Omit it (or send null) when you do not hold it — an empty string is stored as "not stated", never as a country.

Validation and error handling#

Two layers, reporting differently.
Layer 1 — request boundary, HTTP 400. The whole request is refused. Paths are zero-based and prefixed with Parcel.:
Parcel.Items[0].OriginCountryCode: The length of 'Origin Country Code' must be 2 characters or fewer.
Over-length skuCode, nsCode and spCode are refused here too.
Layer 2 — parcel errors, HTTP 200 with hasErrors: true. The parcel is stored but flagged, and handling is skipped until you fix it. Your value is kept so you can see what you sent. Paths are one-based, no prefix:
ErrorCause
Items[1].SpCode: cannot be empty when SpCodeNotApplicable is falseAsserted a barcode exists but sent none
Items[1].SpCode: must be empty when SpCodeNotApplicable is trueClaimed the Y081 exemption but also sent a barcode
Items[1].OriginCountryCode: not validTwo characters, but not a recognised country code
📌 Watch the index bases. The same item is Items[0] in a boundary error and Items[1] in a parcel error. Different validators, not a typo.
A contradiction is reported rather than silently corrected: clearing your spCode because you also sent spCodeNotApplicable: true would make PostPlus file a Y081 exemption you never intended.
Spreadsheet uploads differ on length. There is no request boundary, so an over-long identifier is truncated instead of rejecting the parcel. API callers get the 400 above; nothing is truncated.
From 1 November, completeness is enforced in addition: a parcel missing a mandatory identifier is rejected at submission.

Customs, after filing#

There is no real-time EU database check of PID values — no central product register. Accuracy is assessed on risk analysis: plausibility against the description, HS code and value.
If customs raises a discrepancy, we email your operational contacts with the parcel number and reason and flag the parcel in tracking; you return corrected item data; we amend or re-lodge, and the parcel is released on acceptance. Each parcel travels under its own declaration, so a hold attaches to that parcel only — it does not block the consolidated manifest or the MAWB. Unresolved parcels stay in temporary storage for at most 90 days, then must be re-exported, returned or destroyed at the shipper's cost, though cases normally resolve well before that.
There is no EU-level PID fine schedule; sanctions for incomplete declarations are national law. Until 31 October the no-sanction safe harbour applies; from 1 November the real risk is non-clearance — holds and delays — rather than a defined fine.

Reading back what we stored#

The create/update response echoes the items as stored, so it is where you verify what we hold, including normalisation such as a stripped spCode space or an upper-cased originCountryCode.
The read endpoints return them only when you ask for items: pass IncludeItems=true on GET /api/v1/parcels/{id}, the …-nrs lookups or /query. Without it the response gives parcelItems as a count and an empty items array — the default for every item field, not something specific to the identifiers.
spCodeNotApplicable comes back as null when never stated, and as true/false when it was; the three states survive the round trip.

Catalogue readiness#

The API change is small — sourcing the values is the real work.
SituationWhat to do
Barcode knownspCode = barcode, spCodeNotApplicable = false
Product genuinely has no barcode (unbranded, bulk, custom-made)spCode empty, spCodeNotApplicable = true
Barcode exists but you do not hold itA data-sourcing task, not an exemption. Do not send true — that is a false Y081 claim. Omit both fields until you have the value.
No manufacturer part numberAsk the supplier to assign an internal reference. nsCode has no exemption, so it cannot be left empty after 1 November.
Prioritise supplier outreach for the part of your catalogue with neither a barcode nor a manufacturer reference — the only group that needs someone else to act before you can comply.

Manifest file uploads#

If you manifest by uploading a spreadsheet, the identifiers are available as columns NsCode, SpCode, SpCodeNotApplicable and OriginCountryCode.
SpCodeNotApplicable is read as free text: true, yes or 1 claim the exemption. A blank or absent column parses to "not stated", not to false — consistent with the API. This section applies to spreadsheet upload only.

Testing#

The fields are live on test — verify against the test Swagger before you build:
Test environment Swagger
Worth testing explicitly:
an item with a barcode (spCodeNotApplicable: false)
an item without one (true, empty spCode)
an item with neither field set — confirm it is still accepted
a deliberate contradiction — confirm you can read the error out of hasErrors
Because all four fields stay optional until 1 November, you can begin populating them in production as soon as your side is ready.
Previous
Import parcel tracking events
Next
Create or update single parcel.
Built with