Amazon Custom: A ZIP Behind a Signed URL #
Amazon Custom orders carry the personalisation on the order item, not the order, and only on the buyer-info path — the same restricted endpoint that returns buyer PII:
GET /orders/v0/orders/{orderId}/orderItems/buyerInfo
That means you need a Restricted Data Token before you can see it at all. If you're getting nulls, start with the RDT flow — the personalisation field is gated by exactly the same mechanism as buyer name and address.
When it is populated, BuyerCustomizedInfo.CustomizedURL is a signed, expiring link to a ZIP. Download it promptly and store the contents; the URL will not be valid later. Inside:
<orderItemId>.json— the structured customisation payload, the one that matters<orderItemId>.xml— the same data in XML- a small preview JPEG of the personalised product
- a print-ready SVG with the buyer's text already laid out on the product surface
Sizing note: in a real catalogue that mixes personalised and plain SKUs, custom orders can be a small minority of volume — on the order of one in sixty. Sample a full window before concluding the field "doesn't work". A 90-day pull that happens to contain no custom orders looks identical to a broken integration.
The Amazon Trap: version3.0 Silently Loses Text #
This one costs real money, because it fails by omission rather than by error.
The customisation JSON contains two representations of the same order. There's customizationData, a deeply nested tree of *Customization nodes carrying exact geometry, fonts and colours; and there's version3.0.customizationInfo.surfaces[], a much flatter and more inviting structure. Naturally, everyone parses the flat one.
The problem: within version3.0, each area is typed as either TextPrinting or ImagePrinting, and Amazon decides per field which one to emit. A TextPrinting area has a text value you can read. An ImagePrinting area has an SVG and no text value at all.
In one real order, three fields were personalised — a date, a name and a sentiment line. The date came through as TextPrinting with readable text. The name and the sentiment came through as ImagePrinting: rendered into vector art, with the literal characters nowhere in that branch of the payload.
So the rule is: parse version3.0 for convenience, but treat a missing text value as "look elsewhere", not as "empty". Walk the customizationData tree down to its TextCustomization leaves for anything the flat view didn't give you. And keep the SVG regardless — for a print workflow it's often more useful than the characters, because the layout, font and positioning are already resolved.
Etsy: Inline, and Watch the Parse #
Etsy is the humane one. Personalisation arrives inline on the receipt, in transactions[].variations, as name/value pairs alongside the rest of the line item. No second call, no download, no token dance.
Two things to be careful about. First, the same structure carries genuine product variations (size, colour) as well as free-text personalisation — you're matching on the property, and a listing's personalisation field is not guaranteed to be named the same way across shops. Keying on a display label that a seller can rename is fragile; key on the identifier.
Second, buyer checkout notes are a separate field (message_from_buyer on the receipt) and sellers absolutely do use it for engraving instructions even when a personalisation field exists. If your fulfilment process depends on getting this right, read both.
A parsing bug worth knowing about: it is easy to write a variation parser that keys off the wrong identifier field and silently produces empty personalisation for a subset of orders. It won't throw. It'll just quietly hand your production team blank engravings for some orders and correct ones for others — which reads as a data problem, not a code problem, and can survive a long time. Assert non-empty on orders you know are personalised.
eBay: It Is Not in the Fulfillment API #
Here's the one that surprises people. eBay's Sell Fulfillment API has no first-class buyer-personalisation field. Scan a full set of orders and you'll find variationAspects null and properties carrying only things like buyer protection and campaign flags. There is no buyer-checkout-message field in the response at all.
Which means the answer depends entirely on how the listing was built. In priority order:
- Listing variation. If the seller created an actual "Personalisation" or "Engraving" variation on the listing, the buyer's choice appears in
lineItems[].variationAspects[]as name/value pairs. Structured, reliable — this is what you want, and it's worth asking the seller to restructure their listings to get it. - SKU convention. Some sellers encode the variant in the custom SKU. Workable but brittle, and it can't carry free text.
- Buyer checkout message. If the seller relies on buyers typing instructions at checkout, that message exists only in the legacy Trading API, as
BuyerCheckoutMessageon itsGetOrderscall. The modern REST Fulfillment API will not give it to you.
Option three is the expensive one: it means adding a second, legacy API integration alongside your REST one purely to read a single field. Before you scope that work, confirm with the seller which mechanism their listings actually use — the answer is frequently "we thought it was in the API" when it never was. The full response shape is in eBay's getOrders reference; connecting the account is covered in the eBay OAuth walkthrough.
Designing One Field for Three Shapes #
You need a single internal representation your fulfilment team reads, regardless of source. What has worked well:
- Store the normalised pairs — an ordered list of
{label, value}per line item, which all three sources can be mapped onto. - Store the raw payload too. Keep the original JSON or ZIP contents. When a print comes out wrong, the argument is settled in seconds instead of hours, and re-parsing historical orders after a bug fix becomes possible.
- Persist the artwork. Amazon's print-ready SVG is genuinely valuable output. Fetch it at sync time, because the signed URL expires.
- Flag "personalised but empty" loudly. A made-to-order SKU with no personalisation text is an exception that must reach a human before the item is produced — not a row that quietly reaches the production queue blank.
Running made-to-order across several marketplaces? This normalisation is the difference between a fulfilment team that trusts the system and one that double-checks every order by hand. See how the same four APIs differ on authentication, or talk to me about the integration.
FAQ #
Where is Amazon Custom personalisation data in SP-API?
On the order item, via GET /orders/v0/orders/{orderId}/orderItems/buyerInfo, in the field BuyerCustomizedInfo.CustomizedURL. That is a signed, expiring link to a ZIP containing the customisation JSON, an XML copy, a preview image and a print-ready SVG. It requires a Restricted Data Token.
Why is the buyer's engraving text missing from the Amazon customisation JSON?
Because you are probably reading only version3.0.customizationInfo.surfaces[]. Amazon emits some fields as ImagePrinting, which contains an SVG but no text value. Fall back to the customizationData tree and read its TextCustomization leaves for any field the flat view didn't provide.
Does eBay's Fulfillment API return buyer personalisation?
Not as a dedicated field. If the listing uses a variation, the value appears in lineItems[].variationAspects[]. A buyer's free-text checkout message is not in the REST Fulfillment API at all — it exists only in the legacy Trading API as BuyerCheckoutMessage.
How does Etsy return personalisation?
Inline on the receipt, in transactions[].variations as name/value pairs, with no additional API call. Buyer checkout notes come separately in message_from_buyer, and sellers often use that field for instructions too.
How long does Amazon's CustomizedURL stay valid?
It is a signed URL that expires, so treat it as single-use: download and persist the ZIP contents during the sync that discovered the order rather than storing the link for later.
Related guides
Marketplace APIs
eBay OAuth: RuName Is Not a Redirect URI (Connecting a Seller Account)
Your eBay consent URL keeps failing with an invalid redirect_uri, and the value you're sending looks perfectly correct. It is — it's just the wrong kind of value. eBay expects a RuName, not your callback URL. Here's the full flow for connecting one seller account: keyset, the legal-address gate, scopes, token exchange, and the first getOrders call.
Read guide →Marketplace APIs
Amazon vs Etsy vs Walmart vs eBay: Four Marketplace APIs, Four Auth Models
If you're integrating more than one marketplace, the authentication layer is where your abstraction breaks first. All four use OAuth 2.0 on paper, and no two behave the same way in practice. Here's what actually differs — token lifetimes, rotation, credential ownership — and how those differences should shape your database schema.
Read guide →Marketplace APIs
No Marketplace Gives You a Real Buyer Phone Number (What to Do Instead)
Your carrier API rejects the shipment because the consignee phone is missing, and the order payload simply doesn't contain one. That's not a bug in your integration — Etsy and Walmart don't return a buyer phone at all, and Amazon's is a relay number. Here's what each marketplace actually gives you and how to satisfy the carrier without inventing data.
Read guide →Don't want to build this yourself?
I set this up for sellers and agencies every week. Book a free 30-minute audit of your Amazon data & PPC setup — you'll leave with a plan either way, whether we work together or not.