Create Content
Add new content items to your catalog. Supports all content types: PDF, EPUB, audiobooks, physical products, and external links.
Endpoint
POST /api/v3/content
Request Body
Required Fields
| Field | Type | Description |
|---|---|---|
name | string | Content title (max 255 chars) |
file_type | string | Content type: pdf, epub, audio, physical |
lang | string | ISO 639-1 language code. See Supported Content Languages |
Optional Fields
| Field | Type | Description |
|---|---|---|
description | string | Full content description (HTML allowed) |
published_at | string | Publication date (YYYY-MM-DD only) |
audience | string | Target audience |
subtitle | string | Content subtitle (max 255 chars) |
publication_place | string | Place of publication (max 255 chars) |
edition_year | integer | Edition year (4 digits, e.g., 2025) |
Identifiers
| Field | Type | Description |
|---|---|---|
identifiers | array | Array of identifier objects (max 20) |
identifiers[].type | string | Identifier type: isbn_digital, isbn_printed, uuid, ddc, external_id |
identifiers[].value | string | Identifier value (max 255 chars). Validated per type (e.g., ISBN-13 checksum) |
identifiers[].is_primary | boolean | Mark as primary identifier (optional, defaults to false) |
The primary identifier's value is automatically synced to the external_id field for backward compatibility. If no identifier is marked as primary, the first one in the array is auto-promoted. Only one identifier can be marked as primary.
Types isbn_digital, isbn_printed, uuid, and external_id require tenant-level uniqueness — two content items cannot share the same identifier of these types. The ddc type does not require uniqueness.
File Upload (digital content only)
| Field | Type | Description |
|---|---|---|
file | string | Storage path to uploaded file (mutually exclusive with file_url) |
file_url | string | External URL to download file from (mutually exclusive with file) |
cover | string | Storage path to uploaded cover image (mutually exclusive with cover_url) |
cover_url | string | External URL for cover image (mutually exclusive with cover) |
file_url/cover_url: Provide a publicly accessible URL. The platform will download the file automatically.file/cover: Provide a storage path from SFTP upload. Contact support to enable SFTP access for your account.
Files are processed asynchronously. The content is created immediately with conversion_status: awaiting. Use Get Content to poll for processing completion.
Multitrack Audio
For audiobooks split into multiple tracks, you can provide the full track list inline at creation time using files, as an alternative to creating tracks one by one with the Audiobook Tracks API. Use files instead of file/file_url; if both are sent, files takes precedence and the single-file input is ignored.
| Field | Type | Description |
|---|---|---|
files | array | Track list (only valid when file_type is audio) |
files[].name | string | Filename of the track (required) |
files[].url | string | External URL to download the track from (required) |
files[].duration | number | Track duration in seconds (optional, min: 0) |
files[].order | integer | Playback order (optional, min: 0) |
files[].track_title | string | Display title of the track (optional, max 255 chars) |
Each track is downloaded from its url and persisted by a background batch. The response returns conversion_status: awaiting. Track duration is recalculated server-side from the downloaded audio (any value sent in files[].duration is overwritten). Poll Get Content until conversion_status becomes done to know when all tracks are ready.
Pricing
| Field | Type | Description |
|---|---|---|
prices | array | Price array: [{currency_id, amount}] |
Prices support starts_at and ends_at fields for scheduled pricing: [{currency_id, amount, starts_at, ends_at}]. Dates should be in YYYY-MM-DD format.
Access Settings
| Field | Type | Description |
|---|---|---|
free | boolean | Enable free access |
free_until | string | Free access expiration (YYYY-MM-DD) |
require_login | boolean | Require login for free access |
preview | boolean | Enable content preview |
preview_require_login | boolean | Require login for preview |
Subscribers-Only Access
| Field | Type | Description |
|---|---|---|
subscribers_only | boolean | Restrict purchase to users with an active plan. Default: false |
Content flagged as subscribers_only cannot coexist with the retail marketplace license. If the content is already listed in the marketplace with a retail license, enabling subscribers_only automatically removes the retail license to keep the configuration consistent. Other licenses (e.g., ppu) are preserved.
Marketplace
| Field | Type | Description |
|---|---|---|
show_in_marketplace | boolean | Make content available in the Publica.la marketplace. When true, the content is listed for other tenants to discover and add to their stores. Defaults to false if not provided. |
Metadata
| Field | Type | Description |
|---|---|---|
author | array | Author names: [{first_name, last_name?, title?}]. See Author names below |
publisher | array | Publisher names (max 200 chars each) |
keywords | array | Keywords/tags (max 200 chars each) |
bisac | array | BISAC codes: [{code: "FIC000000"}] (max 4 codes) |
thema | array | Thema subject codes (strings, max 200 chars each) |
category | array | Category names (max 200 chars each) |
collection | array | Collection names (max 200 chars each) |
series | array | Series names (max 200 chars each) |
country | array | Country names (max 200 chars each) |
edition | array | Edition names (max 200 chars each) |
narrator | array | Narrator names for audiobooks (max 200 chars each) |
publishing_group | array | Publishing group names (max 200 chars each) |
accessibility_features | array | Accessibility features: [{code: "04", description?: "..."}] (code max 3 chars, description max 5000 chars) |
custom_metadata | object | Custom taxonomy groups: {"group_slug": ["value1", "value2"]} |
share_with_tenants_ids | array | Tenant IDs (strings) to share this content with. See Content Sharing |
format_group_ids | array | Format group IDs (strings) to associate this content with |
pages | integer | Number of pages (min: 0). Applies to any file_type. For PDF and audio content the value is derived from the file during processing; input is ignored for those types. |
Author names
author accepts structured names, so the first name, last name, and title are stored separately:
"author": [
{ "first_name": "Jane", "last_name": "Smith" },
{ "title": "Dr.", "first_name": "Ana", "last_name": "Reyes" }
]
first_nameis required.last_nameandtitleare optional.- Each part is a string, max 200 characters.
- Other metadata arrays (
publisher,narrator,keywords, and so on) stay plain strings. - Responses return each author as the composed full name (for example,
"Dr. Ana Reyes").
Geographic Restrictions
| Field | Type | Description |
|---|---|---|
geographic_restrictions | object | {included: [...], excluded: [...]} |
Physical Product Fields
| Field | Type | Description |
|---|---|---|
binding_type | string | Binding type (hardcover, paperback, etc.) |
height | float | Height in cm (min: 0) |
width | float | Width in cm (min: 0) |
weight | float | Weight in grams (min: 0) |
stock | boolean | In stock status |
editing_location | string | Editing/printing location |
thickness | float | Thickness in cm (min: 0) |
Request Examples
Basic PDF Content
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Introduction to Machine Learning",
"file_type": "pdf",
"lang": "en",
"file_url": "https://example.com/files/ml-intro.pdf",
"identifiers": [
{ "type": "isbn_digital", "value": "978-1-234-56789-0", "is_primary": true }
]
}'
EPUB with Full Metadata
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "The Complete Guide to Digital Publishing",
"file_type": "epub",
"lang": "en",
"description": "<p>A comprehensive guide to digital publishing...</p>",
"published_at": "2025-01-15",
"file_url": "https://example.com/files/publishing-guide.epub",
"cover_url": "https://example.com/covers/publishing-guide.jpg",
"prices": [
{ "currency_id": "USD", "amount": 19.99 },
{ "currency_id": "EUR", "amount": 17.99 }
],
"author": [
{ "first_name": "Jane", "last_name": "Smith" },
{ "first_name": "John", "last_name": "Doe" }
],
"publisher": ["Tech Publishing House"],
"keywords": ["publishing", "digital", "ebooks"],
"bisac": [
{ "code": "COM000000" }
],
"identifiers": [
{ "type": "isbn_digital", "value": "978-0-987-65432-1", "is_primary": true }
]
}'
Content with Multiple Identifiers
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Advanced Data Structures",
"file_type": "epub",
"lang": "en",
"file_url": "https://example.com/files/data-structures.epub",
"identifiers": [
{ "type": "isbn_digital", "value": "978-0-306-40615-7", "is_primary": true },
{ "type": "ddc", "value": "005.73" }
]
}'
Free Content with Expiration
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Sample Chapter - Preview Edition",
"file_type": "pdf",
"lang": "en",
"file_url": "https://example.com/samples/chapter1.pdf",
"free": true,
"free_until": "2025-06-30",
"require_login": true
}'
Audiobook
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Mystery Novel - Narrated Edition",
"file_type": "audio",
"lang": "en",
"description": "Award-winning mystery novel, professionally narrated",
"prices": [
{ "currency_id": "USD", "amount": 14.99 }
],
"author": [{ "first_name": "Mystery", "last_name": "Author" }],
"publisher": ["Audiobook Productions"]
}'
After creating an audiobook, use the Audiobook Tracks API to add individual audio tracks.
Physical Product
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Collector Edition Hardcover",
"file_type": "physical",
"lang": "en",
"cover_url": "https://example.com/covers/collector.jpg",
"prices": [
{ "currency_id": "USD", "amount": 49.99 }
],
"binding_type": "hardcover",
"pages": 450,
"height": 24.5,
"width": 16.0,
"weight": 650,
"stock": true
}'
Content with Geographic Restrictions
curl -X POST "https://yourstore.publica.la/api/v3/content" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Regional Edition",
"file_type": "epub",
"lang": "es",
"file_url": "https://example.com/files/regional.epub",
"prices": [
{ "currency_id": "USD", "amount": 9.99 }
],
"geographic_restrictions": {
"included": ["AR", "CL", "UY", "MX"],
"excluded": []
}
}'
Response
Success Response (201 Created)
{
"data": {
"id": "468170",
"external_id": "978-1-234-56789-0",
"name": "Introduction to Machine Learning",
"slug": "introduction-to-machine-learning",
"lang": "en",
"file_type": "pdf",
"audience": null,
"subtitle": null,
"publication_place": null,
"edition_year": null,
"cover_url": null,
"reader_url": "https://yourstore.publica.la/reader/introduction-to-machine-learning",
"product_url": "https://yourstore.publica.la/library/publication/introduction-to-machine-learning",
"created_at": "2025-12-23T10:30:00.000000Z",
"updated_at": "2025-12-23T10:30:00.000000Z",
"published_at": "2025-12-23T00:00:00.000000Z",
"license": "retail",
"free": {
"enabled": false,
"until": null,
"require_login": false
},
"preview": {
"enabled": false,
"require_login": false
},
"subscribers_only": false,
"conversion_status": "awaiting",
"prices": [],
"description": null,
"publisher": [],
"author": [],
"bisac": [],
"keywords": [],
"country": [],
"edition": [],
"narrator": [],
"publishing_group": [],
"thema": [],
"series": [],
"category": [],
"collection": [],
"metrics": {
"total_pages": 0,
"total_words": 0,
"total_seconds": 0
},
"custom_metadata": {},
"geographic_restrictions": null,
"identifiers": [
{
"type": "isbn_digital",
"value": "978-1-234-56789-0",
"is_primary": true
}
]
}
}
The create response always includes prices, description, metadata, geographic_restrictions, and identifiers data regardless of the include parameter.
Conversion Status
Digital content undergoes asynchronous processing. Track the status via the conversion_status field returned in the content response.
| Status | Description |
|---|---|
awaiting_* | Content is queued or waiting for processing to begin |
started_* | Processing in progress (varies by file type) |
done | Processing complete, content available |
deferred | Awaiting first user access to trigger processing (bulk imports) |
error_* | Processing failed (varies by file type) |
Do not couple your logic to specific intermediate status values (awaiting_*, started_*, error_*) as they may change without notice. If you need to check whether content is ready, use done as the only stable status to rely on.
Polling for Completion
curl -X GET "https://yourstore.publica.la/api/v3/content/468170" \
-H "X-User-Token: your-api-token"
Error Handling
Validation Errors (422)
{
"message": "The given data was invalid.",
"errors": {
"name": ["The name field is required."],
"file_type": ["The selected file type is invalid."]
}
}
Duplicate Identifier (422)
{
"message": "The given data was invalid.",
"errors": {
"identifiers.0.value": [
"This isbn_digital identifier is already in use as primary for another content."
]
}
}
File Processing Error (422)
{
"message": "The given data was invalid.",
"errors": {
"file_url": ["Unable to download file from the provided URL."]
}
}
Authentication Error (401)
{
"message": "Unauthenticated."
}
Common Validation Rules
| Field | Rules |
|---|---|
name | Required, max 255 chars |
file_type | Required, one of: pdf, epub, audio, physical |
lang | Required, valid language code |
subtitle | Optional, max 255 chars |
publication_place | Optional, max 255 chars |
edition_year | Optional, 4 digits |
description | Optional, max 20,000 chars, HTML allowed |
prices[].currency_id | Valid ISO 4217 currency code |
prices[].amount | Number, min: 0 (zero allowed for free pricing) |
file_url | Valid URL, accessible for download |
published_at | Valid date (YYYY-MM-DD only) |
bisac[].code | Valid BISAC code |
geographic_restrictions.included | Array of ISO 3166-1 alpha-2 country codes |
geographic_restrictions.excluded | Array of ISO 3166-1 alpha-2 country codes |
identifiers | Optional, array, max 20 items |
identifiers[].type | Required, one of: isbn_digital, isbn_printed, uuid, ddc, external_id |
identifiers[].value | Required, max 255 chars. Validated per type (ISBN-10/ISBN-13 checksum, UUID format, DDC format) |
identifiers[].is_primary | Optional, boolean |
subscribers_only | Optional, boolean |
Best Practices
- Use identifiers - Always set identifiers (ISBN, UUID, etc.) for cross-system synchronization
- Poll for completion - Check
conversion_statusbefore assuming content is available - Include complete metadata - Better discoverability with author, publisher, and BISAC codes
- Set prices upfront - Configure pricing at creation to avoid separate update calls
See Also
- Bulk Create - Create multiple items at once
- Update Content - Modify existing content
- Audiobook Tracks - Add tracks to audiobooks
- Overview - API overview