Experience Content Endpoint
Fetch the content entries that back the steps of a single experience.
Request
GET /api/v1/projects/:projectId/experiences/:id/content
| Parameter | In | Description |
|---|---|---|
projectId | path | The project the experience belongs to. |
id | path | The experience to fetch content for. |
preview_token | query | Optional. With it, the endpoint returns preview content, which is unpublished. |
Response
{
"experienceId": "exp_123",
"versionId": "ver_456",
"content": [
{
"id": "entry_789",
"contentModelKey": "page-hero",
"data": {
"title": "Spring sale",
"category": { "contentEntryId": "entry_42", "contentModelKey": "category" }
}
}
],
"references": [
{
"id": "entry_42",
"contentModelKey": "category",
"data": { "name": "Outerwear" }
}
]
}| Field | Type | Description |
|---|---|---|
experienceId | string | The experience the content belongs to. |
versionId | string | null | The published version id, or null on preview. |
content[] | array | The entries that the steps of the experience point at. |
content[].id | string | The content entry id. |
content[].contentModelKey | string | null | The Key of the Model, or null when it cannot be resolved. |
content[].data | object | The entry data. It matches the schema of the Model. |
references[] | array | Every entry that a reference field reaches, in the same blob shape as content[]. |
The published response and the preview response hold the same fields, and the same values, for the same content.
A reference field points at a separate blob
A Reference field arrives as a pointer, and not as the entry:
{ "contentEntryId": "entry_42", "contentModelKey": "category" }A repeatable Reference field arrives as an array of such pointers.
The entry itself arrives in references[] under its own id. Look the pointer up
there. The SDK does this for you, through
useReference and getReference.
references[] holds each entry one time, for any number of fields that point at it. It
omits the entries that are in content[] already.
What references[] omits
Picked resolves a chain of references to a maximum depth of 5. It counts the depth from
the entries in content[]. An entry is absent from references[] when Picked cannot
resolve it:
| Cause | Result |
|---|---|
| The target was deleted | The pointer stays. The entry is absent. |
| The target is in another workspace | The pointer stays. The entry is absent. |
| The chain makes a cycle | The pointer stays. The entry is absent. |
| The chain is deeper than 5 | The pointer stays, with its contentModelKey. The entry is absent. |
A pointer with no entry in references[] means that there is no such entry. Picked sends
no empty blob for it.
An HTML asset comes back in the response
A Model can have an HTML asset field. The
value of that field arrives inside the response. The endpoint changes the reference to
{ id, content }. There, content holds the HTML that you uploaded, as a string. It
is null when the endpoint cannot resolve it:
{
"id": "entry_789",
"contentModelKey": "page-hero",
"data": {
"markup": { "id": "asset_42", "content": "<section>...</section>" }
}
}The SDK renders the inlined HTML directly, with no extra storage fetch.
Status codes
| Code | Meaning |
|---|---|
200 | Success. |
401 | Invalid preview_token. |
404 | The experience has no published content. |
Example
curl https://api.picked.app/api/v1/projects/proj_123/experiences/exp_123/content{
"experienceId": "exp_123",
"versionId": "ver_456",
"content": [
{ "id": "entry_789", "contentModelKey": "page-hero", "data": { "title": "Spring sale" } }
],
"references": []
}Related
- About the two APIs
- About content references — why a reference is a pointer.
- Content — how the SDK resolves a pointer.
- Project config — the endpoint that links a step to an entry.
- Server Snapshot — how the SDK reads this content.
- Preview, cache, and crawlers
