Image pack pulling
Incremental pulling of published image packs
Every time an image pack is "published" on the website, an immutable publication record is created: the version number goes up by one and the document content at that moment is frozen into a snapshot. Your listing tool pulls incrementally by record id and gets the snapshot plus the images. Both endpoints require documents:read; downloading the images additionally requires assets:read.
List publications
GET /api/v1/image-pack-publications?since_id=0&limit=50| Parameter | Description |
|---|---|
since_id | Only return records with id greater than this, default 0 |
limit | Records per page, default 50, maximum 200 |
Returns only the current account's records, in ascending id order.
{
"items": [
{
"id": 42,
"pack_id": "pk_xxxxxxxx",
"version": 3,
"style_code": "QS-2601",
"source_revision": 17,
"published_at": 1757600000000
}
],
"next_since_id": 42,
"reread_overlap": 50,
"dedupe_by": ["pack_id", "version"]
}| Field | Description |
|---|---|
id | Publication record id, globally increasing, used as the cursor |
pack_id | Primary key of the image pack. Use it to decide whether two records are the same product |
version | Which publication of this pack, starting at 1 |
style_code | Style code, for display. The seller can change it and it may repeat; never use it as a key |
source_revision | Which revision of the draft was frozen |
published_at | Publication time, milliseconds since epoch |
next_since_id | Cursor for the next round. With no new records it echoes the since_id you sent |
reread_overlap | Recommended overlap to re-read, see below |
dedupe_by | Deduplication key |
Incremental pulling
Do these three steps. They are a contract, not a suggestion:
- Remember the returned
next_since_id - Next round, start from
next_since_id - reread_overlap, not fromnext_since_id - Deduplicate by
(pack_id, version)
Why re-read with overlap: id is a database sequence, and of two concurrent publications the one that got its id later may commit first. If you read 101 and move the cursor past it, then 100 commits, it is skipped forever. Re-reading the last 50 records closes that window; deduplication makes re-read records harmless. Your system needs deduplication anyway (retries, repeated pulls), so this costs nothing extra.
Polling cadence is under rate limits.
Read one publication
GET /api/v1/image-pack-publications/<id>Returns the fields above plus manifest: the document snapshot at publication time, untouched, except that each image gets an extra download_url.
{
"id": 42,
"pack_id": "pk_xxxxxxxx",
"version": 3,
"style_code": "QS-2601",
"source_revision": 17,
"published_at": 1757600000000,
"manifest": {
"schemaVersion": 3,
"blocks": [
{ "id": "b1", "type": "text", "content": "白底正面,突出面料纹理" },
{
"id": "b2",
"type": "images",
"items": [
{ "imageId": "img_xxxxxxxx", "download_url": "/api/file/xxxxxxxx.png" }
]
}
]
}
}Snapshot structure
blocks are in the order the seller arranged them. There are only two block types:
type | Field | Meaning |
|---|---|---|
text | content | The seller's note to downstream: what this group of images is, how to use it, what to watch for |
images | items[] | Image list, each with imageId and download_url |
Photopurr does not interpret the text blocks or classify the images. Reading them and deciding where each image goes is your side's job.
download_url is a relative path that requires the assets:read scope; usage is on the image download page. Images referenced by a published version are never auto-cleaned. If the seller deleted an image by hand, its download_url is null rather than a URL guaranteed to 404.
Records published early (before 2026-09-10) have schemaVersion 2 and use slots[].items[] instead of blocks. Branch on schemaVersion; these records are never rewritten.
Records that don't belong to the current account return 404.
Cross-checking on the website
Developer Center → Publications lists all your publication records, each with a ready-to-run curl command, so you can compare against what your system pulled.
Photopurr Docs