Products
What you sell and its variants.
This page covers the product object, the variant object and the product compliance object.
Endpoints
- GET
/v2/ products - POST
/v2/ products - GET
/v2/ products/ {id} - PATCH
/v2/ products/ {id} - DELETE
/v2/ products/ {id} - POST
/v2/ products/ {id}/ publish - POST
/v2/ products/ {id}/ unpublish - POST
/v2/ products/ {id}/ variants - PATCH
/v2/ variants/ {id} - DELETE
/v2/ variants/ {id} - POST
/v2/ products/ {id}/ compliance/ documents - DELETE
/v2/ compliance-documents/ {id} - GET
/v2/ products/ {id}/ compliance
The product object
Something you sell: its variants, what they are made of, their prices and margins, and its storefront and review state.
Attributes
- idstring
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it. - objectstring
Names the type of this object. Always
product. - namestring
Display name.
- slugstring
URL-safe name used in the storefront address.
- categoryobject or null
The product category, which decides its safety requirements. Null when none is selected.
- reviewProductReview
Review of the product as a whole: approved once every design and extra in it is approved, rejected if any is rejected.
- publishingProductPublishing
Storefront visibility.
- variant_countinteger
Number of variants.
- price_rangeobject or null
Lowest and highest variant price. Null without variants.
- imagesarray of Image
Product photos.
- created_attimestamp
Point in time, ISO 8601 in UTC.
- updated_attimestamp
Point in time, ISO 8601 in UTC.
- descriptionstring or null
Product description shown on the storefront.
- optionsarray of object
The choices a buyer makes, in display order. Each variant has one value per option.
- variantsarray of Variant
Every variant.
- attachmentsarray of objects
Production documents sent to the production partner with every order.
- storefrontobject
How the product appears on your storefront.
- custom_label_urlstring or null
Your custom label image, printed by the production partner and shipped with the product. Null when none.
- complianceobject
Safety documents at a glance. With
expand[]=complianceit is the full view, identical to what the product compliance endpoint returns.
{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": true,
"unpublished_by": null,
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}List products
GET/
- Credentials
- An API key with the
products:readscope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
list_products
Lists your products, newest first by default. Items leave out variants and storefront details to stay small; get the product for everything, or pass expand[]=variants. Designers only.
Query parameters
- review_statusarray of ReviewStatus
Only products in these review states. Repeat for several, for example
review_status=pending&review_status=rejected.Possible valuespendingapprovedrejected - is_publicstring
Only public (
true) or private (false) products.Possible valuestruefalse - categorystring
Only products in this category.
- searchstring
Only products whose name contains this text, ignoring case.
- updated_aftertimestamp
Only products changed after this time. Use it to sync changes since your last poll.
- sortstring
Order of results. A leading
-means descending.positionis your own order from the dashboard.namesorts alphabetically in a language-aware collation, which compares letters before spaces and case (test slicercomes aftertesting warnings); do not expect byte order.Possible values-created_atcreated_at-updated_atnameposition - limitinteger
How many results per page, from 1 to 100.
- cursorstring
Where to continue from: the
next_cursorof the previous page. Omit for the first page. - expand[]array of string
Replace references with full objects. Repeat the parameter for several paths, for example
expand[]=variants. Unknown paths are rejected withinvalid_expand. An expanded object from another resource needs the read scope of that resource on your API key; without it the reference{ id, object, name }is returned instead, with no error. Herevariants.contents.extraneedsextras:read,variants.contents.stockneedsstocks:read.Possible valuesvariantscategoryvariants.categoryvariants.contents.designvariants.contents.stockvariants.contents.extravariants.contents.materials
Returns200 OK
A page of products.
Responses
- 200
A page of products.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl "https://public-api.dapi.digital/v2/products" \
-H "x-api-key: $DAPI_API_KEY"{
"object": "list",
"data": [
{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": true,
"unpublished_by": null,
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z"
}
],
"has_more": false,
"next_cursor": null
}Create a product
POST/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
create_product
Creates a product with its design files, and optionally its images, attachments and variants, in one request. It is private and its designs are pending review by 3DAPI; publish it once it is approved. Upload files first (purposes design_file, product_image, attachment). Counts toward your plan product limit. Designers only.
Headers
- Idempotency-Keystring
Any unique string, for example a UUID. Sending the same request again with the same key within 24 hours returns the first response without doing anything twice. Reusing a key with a different body is refused with
idempotency_key_reused. A refused request (4xx) frees the key so you can correct and resend it; a server error (5xx) is kept and returned again, because the write may already have happened: check the resource before retrying with a new key.
Request body
- namestringRequired
Display name, shown on the storefront.
- slugstring
URL-safe name for the storefront address, unique across your products. Generated from the name when omitted.
- descriptionstring or null
Product description shown on the storefront. Null for none.
- categorystring or null
The product category, which decides its safety requirements.
- prices_include_vatboolean or null
For EU and UK buyers:
trueprices include VAT,falseVAT is added on top,nullinherits your store setting. - optionsarray of object
The choices buyers make, in display order.
- disclaimersarray of object
Your disclaimers shown on the product page.
- show_compliance_labelsboolean
Whether the category safety labels (warnings, age restriction, risk level, CE mark) are shown on the product page.
truewhen omitted on create. - imagesarray of objects
Product photos, in display order. The list replaces the current images: entries not sent are deleted.
- custom_labelobject or null
A label the production partner prints and ships with the product: new (
upload, purposeproduct_image) or kept (url). Null removes it. - attachmentsarray of objects
Production documents for the farm: new (
upload, purposeattachment) or kept (id). - manufacturingobject
How the product is produced. Applies to every design.
- designsarray of objectRequired
The model files of the product.
- variantsarray of CreateVariantRequest
Variants to create with the product. Up to 200 per product.
Returns201 Created
The new product, private and pending review. Returns the product object.
Responses
- 201
The new product, private and pending review.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
Your plan product limit is reached (
plan_limit_reached);details.fix_urlpoints at upgrading. - 409
The slug or a SKU is already used (
slug_taken,sku_already_used). - 422
A variant breaks a product rule:
option_mismatch,material_not_allowed,material_not_found,extra_not_found,extra_not_approved(a rejected extra),stock_not_found,stock_not_approved,category_not_found,variant_needs_design_or_stock,price_below_minimum(minimum indetails.minimum),currency_not_supported,unknown_design_key,duplicate_design_key,design_not_in_product,too_many_variants; a design names a combination with the wrong slot count (combination_slots_mismatch); an image or attachment to keep is not the product (image_not_found,attachment_not_found,custom_label_not_found,too_many_primary_images); or an upload cannot be used:unknown_upload,upload_expired,upload_purpose_mismatch,upload_missing(an upload id whose file was never sent),upload_already_used(an upload id already used once; each works once). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X POST "https://public-api.dapi.digital/v2/products" \
-H "x-api-key: $DAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "PR Tracker",
"description": "A desk tracker for your personal records.",
"category": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"images": [
{
"upload": "upl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"primary": true
}
],
"manufacturing": {
"assembly_required": true,
"farm_instructions": null
},
"designs": [
{
"key": "body",
"file": {
"upload": "upl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
},
"name": "Tracker body",
"materials": {
"mode": "single",
"allowed": [
"mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
]
}
}
],
"variants": [
{
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"price": {
"amount": 5000,
"currency": "usd"
},
"contents": [
{
"type": "design",
"design": "body",
"quantity": 1,
"materials": [
"mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
]
}
]
}
]
}'{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "pending",
"reason": null
},
"publishing": {
"is_public": false,
"unpublished_by": "seller",
"can_publish": false,
"blockers": [
{
"code": "files_not_approved",
"message": "The design files must be approved by 3DAPI before the product can be made public."
}
]
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}Get a product
GET/
- Credentials
- An API key with the
products:readscope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
get_product
Returns one product with every variant, its contents, pricing and margins, shipping tier, and what blocks publishing. Related designs, stocks, extras, materials, categories and attachments are references; expand them with expand[]. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Query parameters
- expand[]array of string
Replace references with full objects. Repeat the parameter for several paths, for example
expand[]=category. Unknown paths are rejected withinvalid_expand. An expanded object from another resource needs the read scope of that resource on your API key; without it the reference{ id, object, name }is returned instead, with no error. Herevariants.contents.extraneedsextras:read,variants.contents.stockneedsstocks:read.Possible valuescategoryvariants.categoryvariants.contents.designvariants.contents.stockvariants.contents.extravariants.contents.materialsattachmentscompliance
Returns200 OK
The product. Returns the product object.
Responses
- 200
The product.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY"{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": true,
"unpublished_by": null,
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}Update a product
PATCH/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
update_product
Changes the product fields you send. Sends designs back to review by 3DAPI: a new design file; turning assembly on or off (every design); a newly added extra that is not approved yet (every design); and, per design, a change to its custom materials, single or multicolor mode, color count or multi-material (AMS) requirement. Nothing else does. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Request body
- namestring
Display name, shown on the storefront.
- slugstring
URL-safe name for the storefront address, unique across your products. Generated from the name when omitted.
- descriptionstring or null
Product description shown on the storefront. Null for none.
- categorystring or null
The product category, which decides its safety requirements.
- prices_include_vatboolean or null
For EU and UK buyers:
trueprices include VAT,falseVAT is added on top,nullinherits your store setting. - optionsarray of object
The choices buyers make, in display order.
- disclaimersarray of object
Your disclaimers shown on the product page.
- show_compliance_labelsboolean
Whether the category safety labels (warnings, age restriction, risk level, CE mark) are shown on the product page.
truewhen omitted on create. - imagesarray of objects
Product photos, in display order. The list replaces the current images: entries not sent are deleted.
- custom_labelobject or null
A label the production partner prints and ships with the product: new (
upload, purposeproduct_image) or kept (url). Null removes it. - attachmentsarray of objects
Production documents for the farm: new (
upload, purposeattachment) or kept (id). - manufacturingobject
How the product is produced. Applies to every design.
Returns200 OK
The updated product. Returns the product object.
Responses
- 200
The updated product.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 409
The slug is already used (
slug_taken). - 422
Removing an option value a variant still uses (
option_in_use);category_not_found; an image or attachment to keep is not the product (image_not_found,attachment_not_found,custom_label_not_found,too_many_primary_images); or an upload cannot be used:unknown_upload,upload_expired,upload_purpose_mismatch,upload_missing(an upload id whose file was never sent),upload_already_used(an upload id already used once; each works once). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X PATCH "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "PR Tracker v2",
"category": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"manufacturing": {
"assembly_required": false,
"farm_instructions": "Print the lid with the logo facing up."
}
}'{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": true,
"unpublished_by": null,
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}Delete a product
DELETE/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
delete_product
Deletes a product, its designs, images and unused variants, as the dashboard does. Variants that orders reference are kept (marked deleted), and orders keep their own frozen copy of the product, so order history is never lost. Cannot be undone. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Returns200 OK
The product was deleted.
Responses
- 200
The product was deleted.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X DELETE "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY"{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"deleted": true
}Publish a product
POST/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
publish_product
Makes the product public on your storefront. Refused while anything in publishing.blockers remains, which includes an inactive store: you must be registered as a business and have your public store turned on. Counts toward your plan limit of public products. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Headers
- Idempotency-Keystring
Any unique string, for example a UUID. Sending the same request again with the same key within 24 hours returns the first response without doing anything twice. Reusing a key with a different body is refused with
idempotency_key_reused. A refused request (4xx) frees the key so you can correct and resend it; a server error (5xx) is kept and returned again, because the write may already have happened: check the resource before retrying with a new key.
Returns200 OK
The product, now public. Returns the product object.
Responses
- 200
The product, now public.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
Your plan limit of public products is reached (
plan_limit_reached);details.fix_urlpoints at upgrading. - 404
You have no product with this id (
product_not_found). - 409
Something blocks publishing (
cannot_publish);details.blockerslists every blocker with its code and what to do, the same list aspublishing.blockers. - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/publish" \
-H "x-api-key: $DAPI_API_KEY"{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": true,
"unpublished_by": null,
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}Unpublish a product
POST/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
unpublish_product
Takes the product off your storefront. Always allowed. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Headers
- Idempotency-Keystring
Any unique string, for example a UUID. Sending the same request again with the same key within 24 hours returns the first response without doing anything twice. Reusing a key with a different body is refused with
idempotency_key_reused. A refused request (4xx) frees the key so you can correct and resend it; a server error (5xx) is kept and returned again, because the write may already have happened: check the resource before retrying with a new key.
Returns200 OK
The product, now private. Returns the product object.
Responses
- 200
The product, now private.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/unpublish" \
-H "x-api-key: $DAPI_API_KEY"{
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "PR Tracker",
"slug": "pr-tracker",
"category": {
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Desk accessories"
},
"review": {
"status": "approved",
"reason": null
},
"publishing": {
"is_public": false,
"unpublished_by": "seller",
"can_publish": true,
"blockers": []
},
"variant_count": 1,
"price_range": {
"min": {
"amount": 5000,
"currency": "usd"
},
"max": {
"amount": 5000,
"currency": "usd"
}
},
"images": [
{
"url": "https://cdn.example.com/tracker.png",
"primary": true
}
],
"created_at": "2026-04-21T07:34:06Z",
"updated_at": "2026-10-02T11:12:40Z",
"description": "A desk tracker for your personal records.",
"options": [
{
"name": "Color",
"values": [
"Black",
"Blue"
]
}
],
"variants": [
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}
],
"attachments": [
{
"id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "attachment",
"name": "assembly-guide.pdf"
}
],
"storefront": {
"url": "https://dapi.digital/store/acme/pr-tracker",
"show_compliance_labels": true,
"disclaimers": [
{
"title": "Production safety",
"text": "Keep away from heat."
}
]
},
"custom_label_url": null,
"compliance": {
"object": "product_compliance",
"enforced": false,
"complete": false,
"missing": 1
}
}The variant object
An orderable version of a product with its own SKU, price and contents, for example one color.
Attributes
- idstring
Unique identifier of the variant, prefixed with
var_. Treat it as an opaque string: store it and compare it, never parse it. - objectstring
Names the type of this object. Always
variant. - skustring
Your SKU code, unique across your active variants.
- namestring or null
Display name of the variant.
- statusstring
activevariants can be ordered;inactiveones are kept but not sold.Possible valuesactiveinactive - optionsarray of object
Option values, in the product option order.
- categoryobject or null
A category that overrides the product category for this variant only. Null when the variant uses the product category.
- pricingobject
Price and margin for one unit.
- shippingobject
How one unit is charged for shipping. Prices per tier and zone come from the shipping rates.
- contentsarray of objects
What each unit of the variant is made of.
- imageobject or null
Image specific to this variant, if any.
{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}Add a variant
POST/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
create_variant
Adds an orderable variant to a product: its SKU, option values, price and what it is made of. A newly added extra that is not approved yet sends the product designs back to review. Up to 200 variants per product. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Headers
- Idempotency-Keystring
Any unique string, for example a UUID. Sending the same request again with the same key within 24 hours returns the first response without doing anything twice. Reusing a key with a different body is refused with
idempotency_key_reused. A refused request (4xx) frees the key so you can correct and resend it; a server error (5xx) is kept and returned again, because the write may already have happened: check the resource before retrying with a new key.
Request body
- skustringRequired
Your SKU code, unique across your active variants.
- namestring or null
Display name of the variant. Null for none.
- optionsarray of object
One value per product option, using the product option names and values.
- priceobjectRequired
What the buyer pays, at most $100,000.00. Not below the minimum, which covers production, a platform fee of up to 10% and the card fee at its highest rate (2.9% + $0.30, the buyer is not known yet): minimum = (manufacturing + extra parts + $0.30) / (0.90 - 0.029), rounded up to the cent, or no minimum while nothing has a production price yet. A lower price is refused with
price_below_minimum, with the minimum indetails.minimum. Checked when the price or the contents change, so variants saved before this rule keep their price until edited. - prices_include_vatboolean or null
For EU and UK buyers:
truethe price includes VAT,falseVAT is added on top,nullinherits from the product, then your store setting. - categorystring or null
Overrides the product category for this variant. Null uses the product category.
- contentsarray of objectsRequired
What each unit is made of: at least one design or one stock.
- imageobject or null
A variant image, new (
upload) or kept (url). Null for none.
Returns201 Created
The new variant. Returns the variant object.
Responses
- 201
The new variant.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 409
The SKU is already used (
sku_already_used). - 422
option_mismatch,material_not_allowed,material_not_found,extra_not_found,extra_not_approved(a rejected extra),stock_not_found,stock_not_approved,category_not_found,variant_needs_design_or_stock,price_below_minimum(minimum indetails.minimum),currency_not_supported,design_not_in_productortoo_many_variants; or the image upload cannot be used:unknown_upload,upload_expired,upload_purpose_mismatch,upload_missing(an upload id whose file was never sent),upload_already_used(an upload id already used once; each works once). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/variants" \
-H "x-api-key: $DAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sku": "TRACKER-BLACK",
"name": "PR Tracker Black",
"options": [
{
"name": "Color",
"value": "Black"
}
],
"price": {
"amount": 5000,
"currency": "usd"
},
"contents": [
{
"type": "design",
"design": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"quantity": 1,
"materials": [
"mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
]
},
{
"type": "extra",
"extra": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"quantity": 4
}
]
}'{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}Update a variant
PATCH/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
update_variant
Changes the variant fields you send. Set status: inactive to stop selling it without deleting it. Designers only.
Path parameters
- idstringRequired
Unique identifier of the variant, prefixed with
var_. Treat it as an opaque string: store it and compare it, never parse it.
Request body
- skustring
Your SKU code, unique across your active variants.
- namestring or null
Display name of the variant. Null for none.
- optionsarray of object
One value per product option, using the product option names and values.
- priceobject
What the buyer pays, at most $100,000.00. Not below the minimum, which covers production, a platform fee of up to 10% and the card fee at its highest rate (2.9% + $0.30, the buyer is not known yet): minimum = (manufacturing + extra parts + $0.30) / (0.90 - 0.029), rounded up to the cent, or no minimum while nothing has a production price yet. A lower price is refused with
price_below_minimum, with the minimum indetails.minimum. Checked when the price or the contents change, so variants saved before this rule keep their price until edited. - prices_include_vatboolean or null
For EU and UK buyers:
truethe price includes VAT,falseVAT is added on top,nullinherits from the product, then your store setting. - categorystring or null
Overrides the product category for this variant. Null uses the product category.
- contentsarray of objects
What each unit is made of: at least one design or one stock.
- imageobject or null
A variant image, new (
upload) or kept (url). Null for none. - statusstring
inactivekeeps the variant but stops selling it.Possible valuesactiveinactive
Returns200 OK
The updated variant. Returns the variant object.
Responses
- 200
The updated variant.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no variant with this id (
variant_not_found). - 409
The SKU is already used (
sku_already_used), or the variant was imported from a sales channel that owns its SKU and price (variant_managed_by_channel). - 422
option_mismatch,material_not_allowed,material_not_found,extra_not_found,extra_not_approved(a rejected extra),stock_not_found,stock_not_approved,category_not_found,variant_needs_design_or_stock,price_below_minimum(minimum indetails.minimum),currency_not_supportedordesign_not_in_product. The price floor is only checked when the price or the contents change. - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X PATCH "https://public-api.dapi.digital/v2/variants/var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"price": {
"amount": 5500,
"currency": "usd"
},
"status": "active"
}'{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"sku": "TRACKER-BLUE",
"name": "PR Tracker Blue",
"status": "active",
"options": [
{
"name": "Color",
"value": "Blue"
}
],
"category": null,
"pricing": {
"price": {
"amount": 5000,
"currency": "usd"
},
"prices_include_vat": true,
"costs": {
"manufacturing": {
"amount": 332,
"currency": "usd"
},
"extra_parts": {
"amount": 40,
"currency": "usd"
},
"platform_fee": {
"amount": 250,
"currency": "usd"
}
},
"earnings": {
"amount": 4378,
"currency": "usd"
}
},
"shipping": {
"tier": "medium",
"determined_by": "volume",
"chargeable_weight_grams": 820,
"extra_small": false
},
"contents": [
{
"type": "design",
"quantity": 1,
"design": {
"id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "design",
"name": "tracker.3mf"
},
"materials": [
{
"id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "material",
"name": "PLA Blue",
"custom": false
}
]
},
{
"type": "extra",
"quantity": 4,
"unit_price": {
"amount": 10,
"currency": "usd"
},
"extra": {
"id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "extra",
"name": "M3 screw"
}
}
],
"image": null
}Delete a variant
DELETE/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
delete_variant
Removes a variant, as the dashboard does: kept and marked deleted when orders reference it (so order history stays intact), removed otherwise. Either way it stops being sold and no longer appears on the product. Designers only.
Path parameters
- idstringRequired
Unique identifier of the variant, prefixed with
var_. Treat it as an opaque string: store it and compare it, never parse it.
Returns200 OK
The variant was deleted.
Responses
- 200
The variant was deleted.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no variant with this id (
variant_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X DELETE "https://public-api.dapi.digital/v2/variants/var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY"{
"id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "variant",
"deleted": true
}The product compliance object
The EU/UK product safety documents a product needs, what you uploaded for each, and whether they are approved.
Attributes
- objectstring
Names the type of this object. Always
product_compliance. - productProductReference or null
Reference to a product. Pass the matching
expand[]path to receive the full product instead. - enforcedboolean
Whether missing documents block publishing this product right now. Only EU/UK sellers are held to it, and only while document enforcement is switched on by 3DAPI; when true, the product
publishing.blockersincludecompliance_documents_missinguntilcompleteis true. - completeboolean
True when every requirement is approved.
- requirementsarray of ComplianceRequirement
Every document the product categories require, in category order.
- other_documentsarray of ComplianceDocument
Documents uploaded for requirements that no longer apply, for example after a category change. Kept so nothing you uploaded disappears.
{
"object": "product_compliance",
"product": {
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "Action Figure"
},
"enforced": false,
"complete": false,
"requirements": [
{
"key": "material-toxicity-assessment",
"name": "Material Toxicity Assessment",
"status": "approved",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": [
{
"id": "cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "compliance_document",
"name": "toxicity-report.pdf",
"format": "pdf",
"size_bytes": 182344,
"url": "https://files.example.com/compliance/toxicity-report.pdf?signature=abc",
"review": {
"status": "approved",
"reason": null,
"reviewed_at": "2026-10-02T10:00:00Z"
},
"uploaded_at": "2026-10-01T08:00:00Z"
}
]
},
{
"key": "technical-file-and-risk-assessment",
"name": "Technical File & Risk Assessment",
"status": "missing",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": []
}
],
"other_documents": []
}Upload a compliance document
POST/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
upload_compliance_document
Adds a document for one requirement of the product. It is pending review by 3DAPI, and the requirement shows pending_review until then. To replace a document, upload the new one and delete the old one. Returns the whole compliance view. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Headers
- Idempotency-Keystring
Any unique string, for example a UUID. Sending the same request again with the same key within 24 hours returns the first response without doing anything twice. Reusing a key with a different body is refused with
idempotency_key_reused. A refused request (4xx) frees the key so you can correct and resend it; a server error (5xx) is kept and returned again, because the write may already have happened: check the resource before retrying with a new key.
Request body
- requirementstringRequired
The
keyof the requirement this document covers, from the product compliance view or the category. - fileobjectRequired
The document, uploaded first with purpose
compliance_document.
Returns201 Created
The compliance view with the new document. Returns the product compliance object.
Responses
- 201
The compliance view with the new document.
- 400
The request is invalid.
details.errorslists each problem (validation_failed), or anexpand[]path is unknown (invalid_expand). - 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 422
The requirement does not apply to this product (
unknown_requirement);details.requirementslists the valid keys. - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/compliance/documents" \
-H "x-api-key: $DAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"requirement": "material-toxicity-assessment",
"file": {
"upload": "upl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
}
}'{
"object": "product_compliance",
"product": {
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "Action Figure"
},
"enforced": false,
"complete": false,
"requirements": [
{
"key": "material-toxicity-assessment",
"name": "Material Toxicity Assessment",
"status": "approved",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": [
{
"id": "cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "compliance_document",
"name": "toxicity-report.pdf",
"format": "pdf",
"size_bytes": 182344,
"url": "https://files.example.com/compliance/toxicity-report.pdf?signature=abc",
"review": {
"status": "approved",
"reason": null,
"reviewed_at": "2026-10-02T10:00:00Z"
},
"uploaded_at": "2026-10-01T08:00:00Z"
}
]
},
{
"key": "technical-file-and-risk-assessment",
"name": "Technical File & Risk Assessment",
"status": "missing",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": []
}
],
"other_documents": []
}Delete a compliance document
DELETE/
- Credentials
- An API key with the
products:writescope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
delete_compliance_document
Removes a document you uploaded. Returns the compliance view of its product, so you see which requirements it leaves missing. Designers only.
Path parameters
- idstringRequired
Unique identifier of the compliance document, prefixed with
cdc_. Treat it as an opaque string: store it and compare it, never parse it.
Returns200 OK
The compliance view without the document. Returns the product compliance object.
Responses
- 200
The compliance view without the document.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no compliance document with this id (
compliance_document_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl -X DELETE "https://public-api.dapi.digital/v2/compliance-documents/cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
-H "x-api-key: $DAPI_API_KEY"{
"object": "product_compliance",
"product": {
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "Action Figure"
},
"enforced": false,
"complete": false,
"requirements": [
{
"key": "material-toxicity-assessment",
"name": "Material Toxicity Assessment",
"status": "approved",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": [
{
"id": "cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "compliance_document",
"name": "toxicity-report.pdf",
"format": "pdf",
"size_bytes": 182344,
"url": "https://files.example.com/compliance/toxicity-report.pdf?signature=abc",
"review": {
"status": "approved",
"reason": null,
"reviewed_at": "2026-10-02T10:00:00Z"
},
"uploaded_at": "2026-10-01T08:00:00Z"
}
]
},
{
"key": "technical-file-and-risk-assessment",
"name": "Technical File & Risk Assessment",
"status": "missing",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": []
}
],
"other_documents": []
}Get product compliance
GET/
- Credentials
- An API key with the
products:readscope (full access includes every scope). A signed-in dashboard session works too. - For
- Designers
- Operation id
get_product_compliance
Returns every safety document the product categories require, the documents you uploaded for each and their review status. Use it to see what is still missing before publishing to EU/UK buyers. Designers only.
Path parameters
- idstringRequired
Unique identifier of the product, prefixed with
prd_. Treat it as an opaque string: store it and compare it, never parse it.
Returns200 OK
The compliance view. Returns the product compliance object.
Responses
- 200
The compliance view.
- 401
Credentials are missing (
missing_credentials), the API key is unknown or inactive (invalid_api_key), the session expired (invalid_session), or both a key and a session were sent (ambiguous_credentials). - 403
The credentials are valid but not allowed to do this: a scope is missing (
missing_scope), the endpoint is for another kind of account (actor_not_allowed) or another kind of credential (credential_not_allowed), the account may no longer use the API (account_blacklisted), or the account must change something first, in which casedetails.fix_urllinks to the dashboard page that fixes it. - 404
You have no product with this id (
product_not_found). - 429
Too many requests (
rate_limited): the limit is 500 per minute per API key (or signed-in user). Wait for the number of seconds in theRetry-Afterheader, then retry;detailshaslimit,window_seconds,reset_atandretry_after_seconds.
Errors use the error object.
curl "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/compliance" \
-H "x-api-key: $DAPI_API_KEY"{
"object": "product_compliance",
"product": {
"id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "product",
"name": "Action Figure"
},
"enforced": false,
"complete": false,
"requirements": [
{
"key": "material-toxicity-assessment",
"name": "Material Toxicity Assessment",
"status": "approved",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": [
{
"id": "cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "compliance_document",
"name": "toxicity-report.pdf",
"format": "pdf",
"size_bytes": 182344,
"url": "https://files.example.com/compliance/toxicity-report.pdf?signature=abc",
"review": {
"status": "approved",
"reason": null,
"reviewed_at": "2026-10-02T10:00:00Z"
},
"uploaded_at": "2026-10-01T08:00:00Z"
}
]
},
{
"key": "technical-file-and-risk-assessment",
"name": "Technical File & Risk Assessment",
"status": "missing",
"required_by": [
{
"id": "cat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
"object": "category",
"name": "Action Figures & Dolls"
}
],
"documents": []
}
],
"other_documents": []
}