Product Publishing Dates v4
Sub-resource of products holding the dated milestones of a title: when it is published, when a sales embargo lifts, when it may be announced to the trade or the public, when it goes out of print. Each entry is one date with one meaning, for one product format.
The meaning of a date is a role code from ONIX
Codelist 163. An entry is identified by the product,
the product_type, the publishing_date_role_code and, optionally, a set of channels.
Formats are dated independently, so an e-book and its printed counterpart carry separate
entries even when the date is the same.
Endpoints
GET /resource/v4/products/{product_id}/publishing_dates
Retrieve publishing dates for a product
Description
Returns all publishing-date records for the product, across every format and role, paginated. Most products return one or two entries.
Only two filters are supported, and any other query parameter is rejected with
400 Bad Request rather than ignored:
?product_type=ebook— narrow to one format.?channels=/?channels__contains=…— narrow by channel scope.
There is no filter on publishing_date_role_code and none on publishing_date, so
selecting "the publication date of the e-book" means fetching the product's records
and filtering client-side. The sort parameter is accepted but has no effect;
records come back in creation order. See
Resource Queries for the query syntax.
Input parameters
Path parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
product_id |
string | No | UUID of the product. |
Query parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
channels |
string | No | Exact match on the whole channel list. The value is normalised the same way as the field itself — lower-cased, de-duplicated, sorted — so `spotify,itunes` and `itunes,spotify` are equivalent. An empty value (`?channels=`) selects the records that are not scoped to any channel, which in practice is nearly all of them. | |
channels__contains |
string | No | Filter to records whose channel list contains the given value, e.g. `?channels__contains=itunes`. Several comma-separated values are combined with AND, so `itunes,spotify` returns only records scoped to both. Note that this is a substring match rather than a match on whole entries: `?channels__contains=book` also matches `bookbeat` and `bookwire`. | |
product_type |
string | No | Filter by product format, e.g. `ebook`, `book`, `audiobook`, `nonbook`. Matched case-insensitively, since values are normalised to lower case. |
Responses
{
"_links": {},
"_pagination": {},
"items": [
{
"_id": "888ffcf3-e685-4e4c-9999-b207a925d6e3",
"_version": "4.0",
"_links": {},
"_legacy_id": 133777,
"product_type": "ebook",
"publishing_date_role_code": "01",
"publishing_date": "2021-07-30",
"channels": [],
"created": 1779195413
}
]
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"properties": {
"_links": {
"type": "object"
},
"_pagination": {
"type": "object"
},
"items": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
}
},
"required": [
"_links",
"_pagination",
"items"
]
}
POST /resource/v4/products/{product_id}/publishing_dates
Create a publishing date
Description
Creates one publishing-date record. product_type, publishing_date_role_code and
publishing_date are all required in practice — none of them has a usable default,
and an omitted or empty product_type fails validation. channels may be omitted,
which scopes the date to every channel.
The example below sets a sales embargo ("02") on the e-book for Apple Books and
Kobo only: those two partners may not sell before 1 February 2026, while every
other channel is governed by whatever unscoped records the product carries.
Input parameters
Path parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
product_id |
string | No | UUID of the product. |
Request body
{
"product_type": "ebook",
"publishing_date_role_code": "02",
"publishing_date": "2026-02-01",
"channels": [
"itunes",
"spotify"
]
}
Schema of the request body
{
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
Responses
{
"_id": "888ffcf3-e685-4e4c-9999-b207a925d6e3",
"_version": "4.0",
"_links": {},
"_legacy_id": 133777,
"product_type": "ebook",
"publishing_date_role_code": "01",
"publishing_date": "2021-07-30",
"channels": [],
"created": 1779195413
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
{
"errors": [
{
"_id": "string",
"stack_trace": [
"string"
],
"message": "string",
"vars": {}
}
]
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"required": [
"errors"
],
"properties": {
"errors": {
"type": "array",
"description": "List of errors occurred",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"_id",
"message",
"stack_trace",
"vars"
],
"properties": {
"_id": {
"type": "string",
"description": "The identifier of the error"
},
"stack_trace": {
"type": "array",
"description": "A stacktrace of the error occurred. Only for testing systems.",
"items": {
"type": "string"
}
},
"message": {
"type": "string",
"description": "A translated message of the error"
},
"vars": {
"type": "object",
"description": "A dict containing additional values of the context of the error."
}
}
}
}
}
}
GET /resource/v4/products/{product_id}/publishing_dates/{id}
Retrieve a single publishing date
Description
Returns one record by UUID. A well-formed UUID that belongs to a different product
returns 403 Permission denied, not 404 — the check that the record belongs to
this product is a permission check. 404 Resource not found means the UUID matches
no record at all.
The example is an e-book publication date, and has the shape most records have:
role "01", no channel scope.
Input parameters
Path parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
id |
string | No | UUID of the publishing date record. | |
product_id |
string | No | UUID of the product. |
Responses
{
"_id": "888ffcf3-e685-4e4c-9999-b207a925d6e3",
"_legacy_id": 133777,
"_version": "4.0",
"_links": {
"self": "https://api.openpublishing.com/resource/v4/products/e8659334-e616-11ee-a221-00505699575c/publishing_dates/888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"product_type": "ebook",
"publishing_date_role_code": "01",
"publishing_date": "2021-07-30",
"channels": [],
"created": 1779195413
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
PUT /resource/v4/products/{product_id}/publishing_dates/{id}
Update a publishing date
Description
Updates one record. Despite being a PUT this is a partial update: only the
fields present in the body are applied and every omitted field keeps its current
value. Sending {} changes nothing, and there is no way to clear a field by leaving
it out.
channels is the one field where that matters in practice. Un-scoping a record so
that the date applies to all channels requires an explicit "channels": []; omitting
the key leaves the existing scope in place. null clears nothing here — a null in
place of publishing_date, product_type, publishing_date_role_code or channels
is rejected with 400 Bad Request.
Moving a record to a role or channel scope already occupied by another record of the
same product and format fails with 400 Bad Request; the uniqueness check ignores
the record being updated, so re-saving a record unchanged is always safe.
The example postpones a publication date by a fortnight, sending only the field that changed.
Input parameters
Path parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
id |
string | No | UUID of the publishing date record. | |
product_id |
string | No | UUID of the product. |
Request body
{
"publishing_date": "2025-12-14"
}
Schema of the request body
{
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
Responses
{
"_id": "f2fb25d8-9160-4f35-b569-1b6ac44ad351",
"_legacy_id": 719697,
"_version": "4.0",
"_links": {
"self": "https://api.openpublishing.com/resource/v4/products/e58dacc3-e616-11ee-a221-00505699575c/publishing_dates/f2fb25d8-9160-4f35-b569-1b6ac44ad351"
},
"product_type": "ebook",
"publishing_date_role_code": "01",
"publishing_date": "2025-12-14",
"channels": [],
"created": 1779378856
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"description": "One dated milestone of a product — one ONIX publishing-date role with one date, for one product format and optionally for named distribution channels.",
"properties": {
"_id": {
"type": "string",
"description": "UUID of this publishing date record. Stable for the life of the record.",
"example": "888ffcf3-e685-4e4c-9999-b207a925d6e3"
},
"_version": {
"type": "string",
"description": "API version of the returned resource.",
"example": "4.0"
},
"_links": {
"type": "object",
"description": "HAL-style links. Contains only `self`, the canonical URL of this record."
},
"_legacy_id": {
"type": "integer",
"description": "Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as `_id`; in v4 `_id` is the UUID and the integer moves here.",
"example": 133777
},
"product_type": {
"type": "string",
"description": "The product format this date applies to. Dates are held per format because formats\nare published, embargoed and withdrawn independently, so the same role may appear\nseveral times for one product with different dates. A product with an e-book and a\nprint edition that share a publication date therefore carries *two* records, not one.\n\nValidated against the platform's product types and normalised to lower case; an\nunrecognised value is rejected with `400 Bad Request`. In practice only `ebook`,\n`book`, `audiobook` and `nonbook` are meaningful here — the remaining accepted values\ndescribe order lines rather than publishable formats.\n",
"example": "ebook",
"x-enum-descriptions": {
"ebook": "Digital edition in any e-book file format (EPUB, PDF, MOBI).",
"book": "Printed edition, whether stocked or print-on-demand.",
"audiobook": "Audio edition, downloadable or streamed.",
"nonbook": "Non-book article sold alongside the title (merchandise, media, bundles).",
"print_author": "Author copies of the printed edition.",
"reviewers_copy": "Review copy of the digital edition.",
"shipment": "Shipping charge line. Not a publishable format; no publishing dates apply.",
"fee": "Fee line. Not a publishable format; no publishing dates apply.",
"service": "Service line. Not a publishable format; no publishing dates apply."
}
},
"publishing_date_role_code": {
"type": "string",
"description": "What the date *means*. A two-character code from ONIX\n[Codelist 163, Publishing date role](https://ns.editeur.org/onix/en/163). The full\ncodelist is accepted — 23 codes — and anything else is rejected with\n`400 Bad Request`. Note that these are the ONIX codes themselves, stored and returned\nverbatim including the leading zero: `\"01\"`, not `1` and not `\"publication\"`. Codes\n`32` and `33` postdate Codelist 163 Issue 67 and are accepted even though older\ncopies of the codelist do not list them.\n\nThe two codes that carry the day-to-day traffic:\n\n- `\"01\"` **Publication date** — the nominal publication date, used for planning and\n promotion. In ONIX terms this is *not* by itself a permission to sell: absent an\n embargo, retail sales may begin as soon as the retailer has stock. It is the code\n most products carry.\n- `\"02\"` **Sales embargo date** — the date a retail sales embargo lifts, known in\n some markets as the strict on-sale date. This is the code that tells a retailer\n \"not before this day\". Where it appears it normally accompanies a role `\"01\"`\n record, frequently carrying the same date.\n\nA role `\"02\"` record whose date has passed is a spent embargo rather than an active\nrestriction; nothing re-evaluates it, and such records are common.\n\nThis API maintains no relationship between roles: a record created, updated or\ndeleted here leaves every other record of the product untouched.\n\nThe remaining codes are accepted but exist only where they have been created\nexplicitly. The commercially significant ones:\n\n- `\"09\"` Public announcement date, `\"10\"` Trade announcement date — before these\n dates the metadata is embargoed for internal or trade-only use respectively.\n- `\"11\"` Date of first publication (of the work, not this edition) and `\"20\"` the\n same for the original language of a translation.\n- `\"13\"` Out-of-print / permanently withdrawn date, `\"22\"` Expected availability\n date after a temporary withdrawal.\n- `\"27\"` Preorder embargo date — the earliest date a preorder may be accepted, which\n is a different and usually earlier gate than `\"02\"`.\n- `\"23\"` Review embargo date, `\"25\"` Publisher's reservation order deadline.\n- `\"12\"` / `\"26\"` Latest and forthcoming reprint date, `\"16\"` / `\"21\"` latest and\n forthcoming reissue date, `\"19\"` publication date of the print counterpart,\n `\"28\"` transfer date, `\"29\"` date of production, `\"35\"` CIP date.\n- `\"30\"` / `\"31\"` / `\"32\"` / `\"33\"` Streaming, subscription, download and purchase\n embargo dates — for digital products sold through more than one consumption model,\n where one model becomes available later than another.\n\n**Uniqueness.** Within one product and `product_type` there may be at most one record\nper role with an empty `channels` list, and two channel-scoped records for the same\nrole must not share a channel. Either collision is rejected with `400 Bad Request`.\nNo role is required to be present, roles need not be in chronological order, and\nthere is no cross-role validation at all: an out-of-print date (`\"13\"`) earlier than\nthe publication date (`\"01\"`) is accepted.\n\n**These dates do not decide availability.** Whether a product is on sale is governed\nby the product's own expected publication date per format, which the v3 product\nresource exposes as `publication_date` and the v4 product resource does not expose at\nall. Creating a role `\"01\"` record here does not make a product available, and\ndeleting one does not withdraw it.\n",
"example": "01"
},
"publishing_date": {
"type": "string",
"format": "date",
"nullable": false,
"description": "The date itself, as a plain calendar date in `YYYY-MM-DD` form. Always returned in\nexactly that form; there is no time component, no time zone offset, and no\nnormalisation across zones. A date is the whole day, inclusive — an embargo dated\n`2026-04-15` lifts *on* 15 April, and an out-of-print date of `2026-04-15` means the\nproduct is withdrawn on that day.\n\n**Partial dates are not supported.** ONIX allows a publishing date to carry a reduced\nprecision such as `2026` or `202604`, declared through the `dateformat` attribute\n([Codelist 55](https://ns.editeur.org/onix/en/55)); this field does not. Source data\nthat names only a month or a year has to be resolved to a single day before it can be\nsent.\n\nInput is more forgiving than the output format suggests: `2026-4-5`, `20260405` and\n`20260405T00:00:00` are all accepted and all come back as `2026-04-05`, with any time\ncomponent discarded. A value that cannot be parsed as a whole day — including `2026`\nand `2026-04` — is rejected with `400 Bad Request`. `YYYY-MM-DD` avoids all of this.\n",
"example": "2021-07-30"
},
"channels": {
"type": "array",
"description": "Distribution channels this date is scoped to. An empty list — by far the normal case —\nmeans the date applies to every channel.\n\nA non-empty list narrows the record to named distribution partners, so that one format\ncan carry different dates for different partners: a title that becomes available on\none retailer a week before it reaches the library platforms, for example.\n\nValues are the platform's distribution-channel slugs. Those in common use are:\n\n- `amazon`\n- `itunes`\n- `kobo`\n- `spotify`\n- `skoobe`\n- `divibib`\n- `overdrive`\n- `bookbeat`\n- `bookwire`\n\nThe list is open-ended — a realm distributes through whichever partners it has\ncontracts with — and it is *not* validated against that vocabulary: a typo is accepted\nas given and will simply never match anything.\n\nValues are lower-cased, de-duplicated and sorted, so\n`[\"Spotify\", \"itunes\", \"itunes\"]` comes back as `[\"itunes\", \"spotify\"]`, and on update the\nlist is replaced wholesale rather than merged.\n\nUniqueness is enforced per channel, so `itunes` and `spotify` may each carry their own\nrole `\"02\"` alongside one unscoped role `\"02\"`.\n",
"items": {
"type": "string"
},
"example": []
},
"created": {
"type": "integer",
"description": "When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006.",
"nullable": true,
"example": 1779195413
}
},
"required": []
}
{
"errors": [
{
"_id": "string",
"stack_trace": [
"string"
],
"message": "string",
"vars": {}
}
]
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"required": [
"errors"
],
"properties": {
"errors": {
"type": "array",
"description": "List of errors occurred",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"_id",
"message",
"stack_trace",
"vars"
],
"properties": {
"_id": {
"type": "string",
"description": "The identifier of the error"
},
"stack_trace": {
"type": "array",
"description": "A stacktrace of the error occurred. Only for testing systems.",
"items": {
"type": "string"
}
},
"message": {
"type": "string",
"description": "A translated message of the error"
},
"vars": {
"type": "object",
"description": "A dict containing additional values of the context of the error."
}
}
}
}
}
}
DELETE /resource/v4/products/{product_id}/publishing_dates/{id}
Delete a publishing date
Description
Removes one record. Nothing else changes: the product's availability is not affected, and no companion record is removed — deleting a role "01" entry leaves any role "02" entry in place.
Input parameters
Path parameters
| Parameter | Type | Default | Nullable | Description |
|---|---|---|---|---|
id |
string | No | UUID of the publishing date record. | |
product_id |
string | No | UUID of the product. |
Responses
{
"errors": [
{
"_id": "string",
"stack_trace": [
"string"
],
"message": "string",
"vars": {}
}
]
}
Schema of the response body
{
"type": "object",
"additionalProperties": false,
"required": [
"errors"
],
"properties": {
"errors": {
"type": "array",
"description": "List of errors occurred",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"_id",
"message",
"stack_trace",
"vars"
],
"properties": {
"_id": {
"type": "string",
"description": "The identifier of the error"
},
"stack_trace": {
"type": "array",
"description": "A stacktrace of the error occurred. Only for testing systems.",
"items": {
"type": "string"
}
},
"message": {
"type": "string",
"description": "A translated message of the error"
},
"vars": {
"type": "object",
"description": "A dict containing additional values of the context of the error."
}
}
}
}
}
}
Schemas
Product Publishing Date
| Name | Type | Description | Example |
|---|---|---|---|
_id |
string |
UUID of this publishing date record. Stable for the life of the record. |
888ffcf3-e685-4e4c-9999-b207a925d6e3 |
_legacy_id |
integer |
Legacy integer identifier of this resource, kept so existing integrations can correlate their own records. This is the value the v3 endpoint returns as |
133777 |
_links |
object |
HAL-style links. Contains only |
|
_version |
string |
API version of the returned resource. |
4.0 |
channels |
Array<string> |
Distribution channels this date is scoped to. An empty list — by far the normal case — means the date applies to every channel. A non-empty list narrows the record to named distribution partners, so that one format can carry different dates for different partners: a title that becomes available on one retailer a week before it reaches the library platforms, for example. Values are the platform's distribution-channel slugs. Those in common use are:
The list is open-ended — a realm distributes through whichever partners it has contracts with — and it is not validated against that vocabulary: a typo is accepted as given and will simply never match anything. Values are lower-cased, de-duplicated and sorted, so
Uniqueness is enforced per channel, so |
[] |
created |
integer| null |
When this record was created, in seconds since the Unix epoch (UTC). This is the creation of the record, not the date it describes — a record created today can perfectly well carry a publication date from 2006. |
1779195413 |
product_type |
string |
The product format this date applies to. Dates are held per format because formats are published, embargoed and withdrawn independently, so the same role may appear several times for one product with different dates. A product with an e-book and a print edition that share a publication date therefore carries two records, not one. Validated against the platform's product types and normalised to lower case; an
unrecognised value is rejected with |
ebook |
publishing_date |
string(date) |
The date itself, as a plain calendar date in Partial dates are not supported. ONIX allows a publishing date to carry a reduced
precision such as Input is more forgiving than the output format suggests: |
2021-07-30 |
publishing_date_role_code |
string |
What the date means. A two-character code from ONIX
Codelist 163, Publishing date role. The full
codelist is accepted — 23 codes — and anything else is rejected with
The two codes that carry the day-to-day traffic:
A role This API maintains no relationship between roles: a record created, updated or deleted here leaves every other record of the product untouched. The remaining codes are accepted but exist only where they have been created explicitly. The commercially significant ones:
Uniqueness. Within one product and These dates do not decide availability. Whether a product is on sale is governed
by the product's own expected publication date per format, which the v3 product
resource exposes as |
01 |