Products

View as Markdown

What you sell and its variants.

This page covers the product object, the variant object and the product compliance object.

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.

    Range at least 0.
  • 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[]=compliance it is the full view, identical to what the product compliance endpoint returns.

The product object
{
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  
}

List products

GET/v2/products

Credentials
An API key with the products:read scope (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. position is your own order from the dashboard. name sorts alphabetically in a language-aware collation, which compares letters before spaces and case (test slicer comes after testing warnings); do not expect byte order.

    Possible values-created_atcreated_at-updated_atnameposition
    Defaults to "-created_at".
  • limitinteger

    How many results per page, from 1 to 100.

    Range 1 to 100. Defaults to 20.
  • cursorstring

    Where to continue from: the next_cursor of 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 with invalid_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. Here variants.contents.extra needs extras:read, variants.contents.stock needs stocks: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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

GET/v2/products
curl "https://public-api.dapi.digital/v2/products" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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/v2/products

Credentials
An API key with the products:write scope (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: true prices include VAT, false VAT is added on top, null inherits 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. true when 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, purpose product_image) or kept (url). Null removes it.

  • attachmentsarray of objects

    Production documents for the farm: new (upload, purpose attachment) 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.errors lists each problem (validation_failed), or an expand[] 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_url points 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 in details.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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

POST/v2/products
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"
          ]
        }
      ]
    }
  ]
}'
Response
{
  "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/v2/products/{id}

Credentials
An API key with the products:read scope (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 with invalid_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. Here variants.contents.extra needs extras:read, variants.contents.stock needs stocks: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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

GET/v2/products/{id}
curl "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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/v2/products/{id}

Credentials
An API key with the products:write scope (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: true prices include VAT, false VAT is added on top, null inherits 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. true when 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, purpose product_image) or kept (url). Null removes it.

  • attachmentsarray of objects

    Production documents for the farm: new (upload, purpose attachment) 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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

PATCH/v2/products/{id}
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."
  }
}'
Response
{
  "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/v2/products/{id}

Credentials
An API key with the products:write scope (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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

DELETE/v2/products/{id}
curl -X DELETE "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "id": "prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "product",
  "deleted": true
}

Publish a product

POST/v2/products/{id}/publish

Credentials
An API key with the products:write scope (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_url points at upgrading.

  • 404

    You have no product with this id (product_not_found).

  • 409

    Something blocks publishing (cannot_publish); details.blockers lists every blocker with its code and what to do, the same list as publishing.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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

POST/v2/products/{id}/publish
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/publish" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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/v2/products/{id}/unpublish

Credentials
An API key with the products:write scope (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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

POST/v2/products/{id}/unpublish
curl -X POST "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/unpublish" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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

    active variants can be ordered; inactive ones 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.

The variant object
{
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  
}

Add a variant

POST/v2/products/{id}/variants

Credentials
An API key with the products:write scope (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 in details.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: true the price includes VAT, false VAT is added on top, null inherits 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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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 in details.minimum), currency_not_supported, design_not_in_product or too_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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

POST/v2/products/{id}/variants
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
    }
  ]
}'
Response
{
  "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/v2/variants/{id}

Credentials
An API key with the products:write scope (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 in details.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: true the price includes VAT, false VAT is added on top, null inherits 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

    inactive keeps 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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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 in details.minimum), currency_not_supported or design_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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

PATCH/v2/variants/{id}
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"
}'
Response
{
  "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/v2/variants/{id}

Credentials
An API key with the products:write scope (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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

DELETE/v2/variants/{id}
curl -X DELETE "https://public-api.dapi.digital/v2/variants/var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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.blockers include compliance_documents_missing until complete is 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.

The product compliance object
{
  ,
  ,
  ,
  ,
  ,
  
}

Upload a compliance document

POST/v2/products/{id}/compliance/documents

Credentials
An API key with the products:write scope (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 key of 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.errors lists each problem (validation_failed), or an expand[] 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 case details.fix_url links 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.requirements lists 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

POST/v2/products/{id}/compliance/documents
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"
  }
}'
Response
{
  "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/v2/compliance-documents/{id}

Credentials
An API key with the products:write scope (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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

DELETE/v2/compliance-documents/{id}
curl -X DELETE "https://public-api.dapi.digital/v2/compliance-documents/cdc_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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/v2/products/{id}/compliance

Credentials
An API key with the products:read scope (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 case details.fix_url links 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 the Retry-After header, then retry; details has limit, window_seconds, reset_at and retry_after_seconds.

Errors use the error object.

GET/v2/products/{id}/compliance
curl "https://public-api.dapi.digital/v2/products/prd_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/compliance" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "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": []
}