Orders in JSON: ph.order/1.2 schema
Versioned order payload ph.order/1.2: published JSON schema, compatibility rules and delivery examples.
When a sale is confirmed, the order is delivered through the integration (webhook, SFTP or email) with this canonical and versioned JSON. This page is the exact specification of the ph.order/1.2 format.
Format rules
- All keys are always present; keys are never omitted.
- null means "unknown data"; it must not be interpreted as 0 (some channels do not break down taxes per line).
- Amounts are numbers with up to 2 decimal places.
- tax_rate is a decimal: 0.21 equals 21%.
- channel is the channel's internal code (e.g. ebay, wllp) and channel_name is its visible name (e.g. Ebay, Wallapop).
- total_gross is the sale price for the seller, seller commission included: channel_fees_gross (what the channel withholds from the seller out of it) and buyer_fees_gross (what the buyer pays the channel on top of the price, never part of total_gross) are informational; so is shipping_gross (shipping), which may or may not be included in total_gross depending on the channel (the lines provide the breakdown of the goods).
Payload example
{
"schema": "ph.order/1.2",
"order_id": "123456789",
"channel": "ebay",
"channel_name": "Ebay",
"created_at": "2026-06-18T10:32:00+00:00",
"status": "accepted",
"currency": "EUR",
"original_currency": "EUR",
"exchange_rate": 1.0,
"customer": {
"foreign_id": "a1b2c3d4",
"first_name": "Toni",
"last_name": "Bosch",
"company_name": null,
"email": "toni.bosch@example.com",
"tax_number": "12345678Z",
"phone": "+34600000000",
"address": {
"street": "Carrer Major 1",
"city": "Campdevànol",
"province": "Girona",
"postal_code": "17530",
"country": "ES"
}
},
"lines": [
{
"external_id": "ITEM-001",
"title": "Faro delantero izquierdo",
"quantity": 1,
"line_net": 100.00,
"line_tax": 21.00,
"line_gross": 121.00,
"tax_rate": 0.21
}
],
"shipping_gross": 10.00,
"channel_fees_gross": 13.00,
"buyer_fees_gross": null,
"total_net": 100.00,
"total_tax": 21.00,
"total_gross": 131.00,
"carrier": "Correos",
"tracking_code": "AB123456789ES",
"tracking_url": "https://tracking.example.com/AB123456789ES",
"payment_method": "card",
"source_account": null
}
Fields
| Field | Type | Description |
|---|---|---|
schema | string | Identifier of the schema and its version, "ph.order/MAJOR.MINOR" (today ph.order/1.2). Look only at the major. |
order_id | string | Unique identifier of the order. |
channel | string | Internal code of the sales channel (e.g. ebay, wllp). |
channel_name | string | Visible name of the sales channel (e.g. Ebay, Wallapop). |
created_at | string | null | Date and time the order was created, in ISO 8601 format. |
status | string | Order status (e.g. accepted). Open list of values. |
currency | string | null | Currency of the order amounts in ISO 4217 format (e.g. EUR). |
original_currency | string | null | Currency the buyer paid in, in ISO 4217 format. When it differs, the order was converted and its amounts are in currency. |
exchange_rate | number | null | Units of original_currency that one unit of currency was worth when the order was converted (e.g. 0.8346 pounds per euro); 1 when it was not converted. |
customer | object | Buyer's details (object; see fields below). |
lines | array | Order lines, one per item (list of objects; see fields below). |
shipping_gross | number | null | Shipping amount with taxes included. |
channel_fees_gross | number | null | Commission the channel withholds from the seller for the order (informational; included in total_gross, the channel deducts it from the payout). |
buyer_fees_gross | number | null | Fees the buyer pays the channel on top of the price, e.g. buyer protection (informational; not part of total_gross). |
total_net | number | null | Total taxable base of the order (excluding taxes). |
total_tax | number | null | Total tax amount of the order. |
total_gross | number | null | Sale price for the seller, taxes and seller commission included (shipping may or may not be included depending on the channel). |
carrier | string | null | Shipping carrier. |
tracking_code | string | null | Shipment tracking code. |
tracking_url | string | null | Shipment tracking URL. |
payment_method | string | null | Payment method (e.g. card). Open list of values. |
source_account | string | null | Source account on the sales channel, if applicable. |
customer.foreign_id | string | null | Buyer's identifier on the source channel. |
customer.first_name | string | null | Buyer's first name. |
customer.last_name | string | null | Buyer's surname. |
customer.company_name | string | null | Buyer's company name, if a business. |
customer.email | string | null | Buyer's email address. |
customer.tax_number | string | null | Buyer's tax identification (NIF/CIF/VAT). |
customer.phone | string | null | Buyer's phone. |
customer.address | object | Buyer's shipping address (object; see fields below). |
customer.address.street | string | null | Street and number of the shipping address. |
customer.address.city | string | null | Town or city of the shipping address. |
customer.address.province | string | null | Province or region of the shipping address. |
customer.address.postal_code | string | null | Postcode of the shipping address. |
customer.address.country | string | null | Country of the shipping address, in ISO 3166-1 alpha-2 format (e.g. ES). |
lines[].external_id | string | null | Item's identifier in the catalogue (SKU or reference). |
lines[].title | string | null | Title or description of the item. |
lines[].quantity | integer | null | Units of the item in this line. |
lines[].line_net | number | null | Taxable base of the line (excluding taxes). |
lines[].line_tax | number | null | Tax amount of the line. |
lines[].line_gross | number | null | Amount of the line with taxes included. |
lines[].tax_rate | number | null | Tax rate of the line as a decimal (0.21 = 21%). |
Compatibility and versions
To avoid having to touch the integration again in future versions, it is best to build the reader following these rules:
- Versioning: the schema field is ph.order/MAJOR.MINOR (today ph.order/1.2). Look only at the MAJOR (the 1) and accept any minor version.
- Published versions: 1.0, the initial schema. 1.1 adds buyer_fees_gross and settles channel_fees_gross as the commission the channel charges the seller on every channel; on Wallapop it held the buyer's protection fee, which moves to buyer_fees_gross. 1.2 adds original_currency and exchange_rate: an order paid in another currency arrives with its amounts in euros, and these fields tell which currency the buyer paid in and at what rate.
- Only added, never removed: within major version 1, changes are additive. New fields may be added (always present, with null when they do not apply), but an existing field will never be removed, renamed, or have its type or meaning changed. The one exception: the 1.1 one noted under the published versions.
- Ignore unrecognised fields: the reader must discard them without failing (do not validate with additionalProperties: false).
- Open lists of values: in status, channel, payment_method, currency and original_currency, new values may appear; handle an unknown value without breaking (e.g. as "other").
- Only a MAJOR version change (ph.order/2.0) would require adaptation, and it would be announced in advance; minor versions require no change on the consumer's part, except for the 1.1 exception noted above.
To validate with a JSON Schema, a lax one is provided for ph.order/1.x that already covers all of this (it accepts new fields and any minor version). To coordinate the change or request the schema and test payloads, contact the person responsible at Portal Hero.