Stocks

View as Markdown

Ready-made units bought in batches.

This page covers the stock object, the stock batch object, the stock purchase object and the region object.

The stock object

Ready-made units you buy in batches ahead of time and that are kept in storage until orders use them. A variant can ship from a stock instead of being printed on demand.

Attributes

  • idstring

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

  • objectstring

    Names the type of this object. Always stock.

  • namestring

    Display name.

  • descriptionstring or null

    Longer description, when provided.

  • reviewReview

    Review by 3DAPI. Anything that will be manufactured is reviewed before it can be sold or produced.

  • units_per_batchinteger

    How many units one purchased batch contains.

    Range at least 0.
  • batch_priceobject or null

    What you pay for one batch, the same in every region. Set by 3DAPI when the stock is approved; null until then.

  • unit_priceobject or null

    What one unit costs you: batch_price divided by units_per_batch. Null until the stock is priced.

  • contentsarray of objects

    What every unit of the stock is made of.

  • inventoryobject

    Units across every batch you bought.

  • restockarray of object

    Restock rule for each region the stock can be produced in. The regions are chosen by 3DAPI at approval.

  • imagesarray of Image

    Photos of the stock.

  • attachmentsarray of objects

    Production documents for this stock.

  • created_attimestamp

    Point in time, ISO 8601 in UTC.

  • updated_attimestamp

    Point in time, ISO 8601 in UTC.

The stock object
{
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  
}

List stocks

GET/v2/stocks

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
list_stocks

Lists your stocks, newest first, with how many units are available and in production. Filter on in_stock=true to see what can ship now. Designers only.

Query parameters

  • review_statusarray of ReviewStatus

    Only stocks in these review states.

    Possible valuespendingapprovedrejected
  • in_stockstring

    Only stocks with (or without) units available to ship.

    Possible valuestruefalse
  • searchstring

    Only stocks whose name contains this text, ignoring case.

  • sortstring

    Order of results. A leading - means descending. 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_atname
    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.

Returns200 OK

A page of stocks.

Responses

  • 200

    A page of stocks.

  • 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/stocks
curl "https://public-api.dapi.digital/v2/stocks" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "object": "list",
  "data": [
    {
      "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "stock",
      "name": "Clicker 50 pack",
      "review": {
        "status": "approved",
        "reason": null,
        "reviewed_at": "2026-05-02T10:00:00Z"
      },
      "units_per_batch": 50,
      "batch_price": {
        "amount": 30000,
        "currency": "usd"
      },
      "unit_price": {
        "amount": 600,
        "currency": "usd"
      },
      "inventory": {
        "available": 32,
        "in_production": 18
      },
      "images": [
        {
          "url": "https://cdn.example.com/clicker.png",
          "primary": true
        }
      ],
      "created_at": "2026-04-30T12:00:00Z",
      "updated_at": "2026-05-02T10:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Create a stock

POST/v2/stocks

Credentials
An API key with the stocks:write scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
create_stock

Creates a stock (ready-made units you buy in batches) and submits it for review. It comes back pending, without a price or regions: 3DAPI sets the batch price and the production regions when approving it. Upload design files first with purpose design_file. Your plan must include prepaid stock. 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.

  • descriptionstring or null

    Longer description. Null for none.

  • units_per_batchintegerRequired

    How many units one batch contains.

    Range 1 to 100000.
  • extrasarray of string

    Your extras packed into every unit. Each counts once per unit. An extra still pending review is accepted and is reviewed with the stock; a rejected one is refused (extra_not_approved).

  • manufacturingobject

    How the stock is produced. Applies to every design.

  • imagesarray of objects

    Stock photos, in display order. On create, every entry is a new upload. On update the list replaces the current images: entries not sent are deleted, and kept ones use the url the stock returns.

  • attachmentsarray of objects

    Production documents for the farm: new (upload, purpose attachment) or kept (id, update only). On update the list replaces the current attachments.

  • designsarray of objectRequired

    The model files of the stock. Add more later with add_stock_design, which sends the stock back to review.

Returns201 Created

The new stock, pending review. Returns the stock object.

Responses

  • 201

    The new stock, 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 does not include prepaid stock, which stocks are part of (plan_limit_reached); details.fix_url points at upgrading.

  • 422

    An extra id is not one of yours (extra_not_found) or names an extra 3DAPI rejected (extra_not_approved, its name in details.extra_name), a material id is not in the catalog (material_not_found), multicolor combinations have different slot counts (slot_count_mismatch), more than one image is primary (too_many_primary_images), an image or attachment is sent as one to keep although a new stock has none yet (unknown_image, unknown_attachment; send { "upload": "upl_..." }), or an upload id is unknown, expired or for another purpose (unknown_upload, upload_expired, upload_purpose_mismatch, upload_missing when the file was never sent, upload_already_used when the upload id was already used 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/stocks
curl -X POST "https://public-api.dapi.digital/v2/stocks" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Clicker 50 pack",
  "units_per_batch": 50,
  "designs": [
    {
      "file": {
        "upload": "upl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
      },
      "name": "Clicker",
      "materials": {
        "mode": "single",
        "allowed": [
          "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
        ]
      }
    }
  ],
  "extras": [
    "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
  ],
  "manufacturing": {
    "assembly_required": true,
    "farm_instructions": "Bag in tens."
  }
}'
Response
{
  "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "stock",
  "name": "Clicker 50 pack",
  "description": "Pre-assembled clickers, bagged.",
  "review": {
    "status": "pending",
    "reason": null,
    "reviewed_at": null
  },
  "units_per_batch": 50,
  "batch_price": null,
  "unit_price": null,
  "contents": [
    {
      "type": "design",
      "design": {
        "id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "design",
        "name": "clicker.3mf"
      }
    },
    {
      "type": "extra",
      "extra": {
        "id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "extra",
        "name": "M3 screw"
      }
    }
  ],
  "inventory": {
    "available": 0,
    "in_production": 0,
    "by_region": []
  },
  "restock": [],
  "images": [
    {
      "url": "https://cdn.example.com/clicker.png",
      "primary": true
    }
  ],
  "attachments": [
    {
      "id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "attachment",
      "name": "packing-guide.pdf"
    }
  ],
  "created_at": "2026-04-30T12:00:00Z",
  "updated_at": "2026-05-02T10:00:00Z"
}

Get a stock

GET/v2/stocks/{id}

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
get_stock

Returns one of your stocks: its price, contents, inventory per region and restock rules. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. 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[]=contents.design. 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 contents.extra needs extras:read.

    Possible valuescontents.designcontents.extraattachments

Returns200 OK

The stock. Returns the stock object.

Responses

  • 200

    The stock.

  • 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 stock with this id (stock_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/stocks/{id}
curl "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "stock",
  "name": "Clicker 50 pack",
  "description": "Pre-assembled clickers, bagged.",
  "review": {
    "status": "approved",
    "reason": null,
    "reviewed_at": "2026-05-02T10:00:00Z"
  },
  "units_per_batch": 50,
  "batch_price": {
    "amount": 30000,
    "currency": "usd"
  },
  "unit_price": {
    "amount": 600,
    "currency": "usd"
  },
  "contents": [
    {
      "type": "design",
      "design": {
        "id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "design",
        "name": "clicker.3mf"
      }
    },
    {
      "type": "extra",
      "extra": {
        "id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "extra",
        "name": "M3 screw"
      }
    }
  ],
  "inventory": {
    "available": 32,
    "in_production": 18,
    "by_region": [
      {
        "region": {
          "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
          "object": "region",
          "name": "Western Europe"
        },
        "available": 32,
        "in_production": 18
      }
    ]
  },
  "restock": [
    {
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "mode": "auto_buy",
      "when_available_below": 10,
      "reorder_units": 50
    }
  ],
  "images": [
    {
      "url": "https://cdn.example.com/clicker.png",
      "primary": true
    }
  ],
  "attachments": [
    {
      "id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "attachment",
      "name": "packing-guide.pdf"
    }
  ],
  "created_at": "2026-04-30T12:00:00Z",
  "updated_at": "2026-05-02T10:00:00Z"
}

Update a stock

PATCH/v2/stocks/{id}

Credentials
An API key with the stocks:write scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
update_stock

Changes the fields you send. Changing units_per_batch or the farm instructions sends the stock back to review; it cannot be bought until approved again. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

Request body

  • namestring

    Display name.

  • descriptionstring or null

    Longer description. Null for none.

  • units_per_batchinteger

    How many units one batch contains.

    Range 1 to 100000.
  • extrasarray of string

    Your extras packed into every unit. Each counts once per unit. An extra still pending review is accepted and is reviewed with the stock; a rejected one is refused (extra_not_approved).

  • manufacturingobject

    How the stock is produced. Applies to every design.

  • imagesarray of objects

    Stock photos, in display order. On create, every entry is a new upload. On update the list replaces the current images: entries not sent are deleted, and kept ones use the url the stock returns.

  • attachmentsarray of objects

    Production documents for the farm: new (upload, purpose attachment) or kept (id, update only). On update the list replaces the current attachments.

Returns200 OK

The updated stock. Returns the stock object.

Responses

  • 200

    The updated stock.

  • 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 stock with this id (stock_not_found).

  • 422

    An extra id is not one of yours (extra_not_found) or names an extra 3DAPI rejected (extra_not_approved, its name in details.extra_name), an image url or attachment id to keep is not one of the stock's (unknown_image, unknown_attachment), more than one image is primary (too_many_primary_images), or an upload id is unknown, expired or for another purpose.

  • 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/stocks/{id}
curl -X PATCH "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "units_per_batch": 50,
  "manufacturing": {
    "assembly_required": true,
    "farm_instructions": "Pack each unit in its own bag."
  }
}'
Response
{
  "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "stock",
  "name": "Clicker 50 pack",
  "description": "Pre-assembled clickers, bagged.",
  "review": {
    "status": "approved",
    "reason": null,
    "reviewed_at": "2026-05-02T10:00:00Z"
  },
  "units_per_batch": 50,
  "batch_price": {
    "amount": 30000,
    "currency": "usd"
  },
  "unit_price": {
    "amount": 600,
    "currency": "usd"
  },
  "contents": [
    {
      "type": "design",
      "design": {
        "id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "design",
        "name": "clicker.3mf"
      }
    },
    {
      "type": "extra",
      "extra": {
        "id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "extra",
        "name": "M3 screw"
      }
    }
  ],
  "inventory": {
    "available": 32,
    "in_production": 18,
    "by_region": [
      {
        "region": {
          "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
          "object": "region",
          "name": "Western Europe"
        },
        "available": 32,
        "in_production": 18
      }
    ]
  },
  "restock": [
    {
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "mode": "auto_buy",
      "when_available_below": 10,
      "reorder_units": 50
    }
  ],
  "images": [
    {
      "url": "https://cdn.example.com/clicker.png",
      "primary": true
    }
  ],
  "attachments": [
    {
      "id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "attachment",
      "name": "packing-guide.pdf"
    }
  ],
  "created_at": "2026-04-30T12:00:00Z",
  "updated_at": "2026-05-02T10:00:00Z"
}

Add a design to a stock

POST/v2/stocks/{id}/designs

Credentials
An API key with the stocks:write scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
add_stock_design

Adds a model file to a stock. Sends the stock back to review. Edit or remove designs with the design operations. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. 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

  • fileobjectRequired

    The model file, uploaded first with purpose design_file.

  • namestring or null

    Display name. The file name when omitted.

  • materialsobjectRequired

Returns201 Created

The new design, pending review. Returns the design object.

Responses

  • 201

    The new design, 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

    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 stock with this id (stock_not_found).

  • 422

    A material id is not in the catalog (material_not_found), multicolor combinations have different slot counts (slot_count_mismatch), or the upload id is unknown, expired or for another purpose.

  • 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/stocks/{id}/designs
curl -X POST "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/designs" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "file": {
    "upload": "upl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
  },
  "name": "Tracker lid",
  "materials": {
    "mode": "single",
    "allowed": [
      "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
    ]
  }
}'
Response
{
  "id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "design",
  "name": "tracker.3mf",
  "owner": {
    "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
    "object": "stock",
    "name": "Clicker 50 pack"
  },
  "review": {
    "status": "pending",
    "reason": null,
    "reviewed_at": null
  },
  "files": [
    {
      "id": "dfl_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "design_file",
      "name": "tracker.3mf",
      "format": "3mf",
      "size_bytes": 2758723,
      "download_url": "https://files.example.com/tracker.3mf?signature=abc",
      "uploaded_at": "2026-04-21T07:34:06Z",
      "production_version": {
        "name": "farm-settings-tracker.3mf",
        "format": "3mf",
        "size_bytes": 2761090,
        "download_url": "https://files.example.com/farm-settings-tracker.3mf?signature=def",
        "prepared_at": "2026-04-21T07:36:40Z"
      }
    }
  ],
  "materials": {
    "mode": "single",
    "allowed": [
      {
        "id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "material",
        "name": "PLA Black",
        "custom": false
      },
      {
        "id": null,
        "object": "material",
        "name": "PETG Matte",
        "custom": true
      }
    ]
  },
  "manufacturing": {
    "colors": 1,
    "requires_ams": false,
    "assembly_required": true,
    "farm_instructions": null,
    "extra_parts_note": "Two M2 screws"
  },
  "created_at": "2026-04-21T07:34:06Z",
  "updated_at": "2026-04-21T09:10:00Z"
}

Set a restock rule

PUT/v2/stocks/{id}/restock/{region_id}

Credentials
An API key with the stocks:write scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
set_stock_restock

Sets what happens when one region runs low (see when_available_below for exactly what is counted). Auto-reorder buys from the same wallet: when a region reaches its restock threshold and auto-reorder is on in your wallet settings, batches are bought automatically (origin: auto_reorder), so keep enough balance for both. Returns the stock with its updated restock list. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

  • region_idstringRequired

    Unique identifier of the region, prefixed with reg_. Treat it as an opaque string: store it and compare it, never parse it.

Request body

  • modestringRequired

    off does nothing, notify emails you when the region runs low, auto_buy buys reorder_units from your wallet (when auto-reorder is on in your wallet settings; otherwise it emails).

    Possible valuesoffnotifyauto_buy
  • when_available_belowinteger or null

    Threshold in units. The rule is checked each time an order draws units from this stock (when the order is assigned for production), not continuously. It counts the units paid for minus the units used in this region, across every batch and including units still in production (so not available), and triggers when that count is at or below this threshold. Required unless mode is off.

    Range 1 to 100000.
  • reorder_unitsinteger or null

    Units to buy per automatic purchase, returned as set. Purchases round up to whole batches: an automatic purchase buys reorder_units divided by units_per_batch, rounded up (at least one batch), at batch_price each, and the batch it creates holds exactly those batches times units_per_batch units. A multiple of units_per_batch buys exactly what you ask for. Required for auto_buy.

    Range 1 to 100000.

Returns200 OK

The stock with the new rule. Returns the stock object.

Responses

  • 200

    The stock with the new rule.

  • 400

    The request is invalid, including a field the mode needs that is missing or one that does not apply to it (validation_failed, details.errors).

  • 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

    auto_buy buys stock, so your plan must include prepaid stock (plan_limit_reached); details.fix_url points at upgrading.

  • 404

    You have no stock with this id (stock_not_found).

  • 422

    The region is not one of the stock regions (region_not_available).

  • 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.

PUT/v2/stocks/{id}/restock/{region_id}
curl -X PUT "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/restock/reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "auto_buy",
  "when_available_below": 10,
  "reorder_units": 50
}'
Response
{
  "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "stock",
  "name": "Clicker 50 pack",
  "description": "Pre-assembled clickers, bagged.",
  "review": {
    "status": "approved",
    "reason": null,
    "reviewed_at": "2026-05-02T10:00:00Z"
  },
  "units_per_batch": 50,
  "batch_price": {
    "amount": 30000,
    "currency": "usd"
  },
  "unit_price": {
    "amount": 600,
    "currency": "usd"
  },
  "contents": [
    {
      "type": "design",
      "design": {
        "id": "dsg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "design",
        "name": "clicker.3mf"
      }
    },
    {
      "type": "extra",
      "extra": {
        "id": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "extra",
        "name": "M3 screw"
      }
    }
  ],
  "inventory": {
    "available": 32,
    "in_production": 18,
    "by_region": [
      {
        "region": {
          "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
          "object": "region",
          "name": "Western Europe"
        },
        "available": 32,
        "in_production": 18
      }
    ]
  },
  "restock": [
    {
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "mode": "auto_buy",
      "when_available_below": 10,
      "reorder_units": 50
    }
  ],
  "images": [
    {
      "url": "https://cdn.example.com/clicker.png",
      "primary": true
    }
  ],
  "attachments": [
    {
      "id": "att_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "attachment",
      "name": "packing-guide.pdf"
    }
  ],
  "created_at": "2026-04-30T12:00:00Z",
  "updated_at": "2026-05-02T10:00:00Z"
}

The stock batch object

One purchase of a stock in one region: how many units were bought, how many are made and how many orders have used.

Attributes

  • idstring

    Unique identifier of the stock batch, prefixed with bat_. Treat it as an opaque string: store it and compare it, never parse it.

  • objectstring

    Names the type of this object. Always stock_batch.

  • stockobject

    The stock this batch is of.

  • regionobject

    Production region holding the units. Orders use units from a region that ships to the buyer.

  • statusStockBatchStatus

    Where the batch is:

    • queued: paid for; production has not started.
    • in_production: the production partner is making the units. Units already made can be used by orders.
    • completed: every unit has been made.
    • used_up: orders have used every unit.
    Possible valuesqueuedin_productioncompletedused_up
  • batchesinteger

    How many batches were bought in this purchase line, at least one. Each holds the stock units_per_batch. An auto_reorder purchase rounds reorder_units up to whole batches.

    Range at least 1.
  • unitsobject

    Unit counts for this batch.

  • price_paidobject

    What you paid for this purchase line, all batches included.

  • unit_priceobject

    What one unit cost you.

  • purchase_referencestring or null

    Reference of the checkout this batch was bought in, shared by every batch bought together and shown on the wallet charge.

  • originstring

    How the batch was bought: manual by you (dashboard or API), auto_reorder automatically from your wallet when a region reached its restock threshold.

    Possible valuesmanualauto_reorder
  • purchased_attimestamp

    When the batch was bought.

  • completed_attimestamp or null

    When every unit was made. Null until then.

The stock batch object
{
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  
}

List batches across stocks

GET/v2/stock-batches

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
list_all_stock_batches

Lists every batch you bought, of any stock, newest first. Use it to see everything in production at once, or every batch bought in one checkout with purchase_reference. Designers only.

Query parameters

  • statusarray of StockBatchStatus

    Only batches in these states. Repeat for several, for example status=queued&status=in_production.

    Possible valuesqueuedin_productioncompletedused_up
  • regionstring

    Only batches held in this region.

  • sortstring

    Order of results. A leading - means newest first.

    Possible values-purchased_atpurchased_at
    Defaults to "-purchased_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.

  • stockstring

    Only batches of this stock.

  • purchased_aftertimestamp

    Only batches bought after this time.

  • purchased_beforetimestamp

    Only batches bought before this time.

  • originstring

    Only batches you bought (manual) or auto-reorder bought.

    Possible valuesmanualauto_reorder
  • purchase_referencestring

    Only batches bought in this checkout, for example ST-8KD2X.

Returns200 OK

A page of batches.

Responses

  • 200

    A page of batches.

  • 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/stock-batches
curl "https://public-api.dapi.digital/v2/stock-batches" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "object": "list",
  "data": [
    {
      "id": "bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "stock_batch",
      "stock": {
        "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "stock",
        "name": "Clicker 50 pack"
      },
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "status": "in_production",
      "batches": 2,
      "units": {
        "purchased": 100,
        "made": 60,
        "used": 20,
        "available": 40
      },
      "price_paid": {
        "amount": 60000,
        "currency": "usd"
      },
      "unit_price": {
        "amount": 600,
        "currency": "usd"
      },
      "purchase_reference": "ST-8KD2X",
      "origin": "manual",
      "purchased_at": "2026-09-30T10:00:00Z",
      "completed_at": null
    }
  ],
  "has_more": false,
  "next_cursor": null
}

List what used a batch

GET/v2/stocks/{id}/batches/{batch_id}/usage

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
list_stock_batch_usage

Lists the orders that took units from one batch, newest first. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

  • batch_idstringRequired

    Unique identifier of the stock batch, prefixed with bat_. Treat it as an opaque string: store it and compare it, never parse it.

Query parameters

  • 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.

Returns200 OK

A page of usage lines.

Responses

  • 200

    A page of usage lines.

  • 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 such stock, or the batch is not one of its batches (stock_not_found, stock_batch_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/stocks/{id}/batches/{batch_id}/usage
curl "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/batches/bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/usage" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "object": "list",
  "data": [
    {
      "order": {
        "id": "ord_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "order",
        "name": "SSG2M9S9"
      },
      "variant": {
        "id": "var_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "variant",
        "name": "Clicker Blue"
      },
      "units": 2,
      "used_at": "2026-10-11T08:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

List the batches of a stock

GET/v2/stocks/{id}/batches

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
list_stock_batches

Lists every batch you bought of one stock, newest first, with how many units are made, used and still available. Use it to follow production and see where your inventory is. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

Query parameters

  • statusarray of StockBatchStatus

    Only batches in these states. Repeat for several, for example status=queued&status=in_production.

    Possible valuesqueuedin_productioncompletedused_up
  • regionstring

    Only batches held in this region.

  • sortstring

    Order of results. A leading - means newest first.

    Possible values-purchased_atpurchased_at
    Defaults to "-purchased_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.

Returns200 OK

A page of batches.

Responses

  • 200

    A page of batches.

  • 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 stock with this id (stock_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/stocks/{id}/batches
curl "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/batches" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "object": "list",
  "data": [
    {
      "id": "bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "stock_batch",
      "stock": {
        "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "stock",
        "name": "Clicker 50 pack"
      },
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "status": "in_production",
      "batches": 2,
      "units": {
        "purchased": 100,
        "made": 60,
        "used": 20,
        "available": 40
      },
      "price_paid": {
        "amount": 60000,
        "currency": "usd"
      },
      "unit_price": {
        "amount": 600,
        "currency": "usd"
      },
      "purchase_reference": "ST-8KD2X",
      "origin": "manual",
      "purchased_at": "2026-09-30T10:00:00Z",
      "completed_at": null
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get a stock batch

GET/v2/stocks/{id}/batches/{batch_id}

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
get_stock_batch

Returns one batch of a stock with its production progress. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the stock, prefixed with stk_. Treat it as an opaque string: store it and compare it, never parse it.

  • batch_idstringRequired

    Unique identifier of the stock batch, prefixed with bat_. Treat it as an opaque string: store it and compare it, never parse it.

Returns200 OK

The batch. Returns the stock batch object.

Responses

  • 200

    The batch.

  • 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 such stock, or the batch is not one of its batches (stock_not_found, stock_batch_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/stocks/{id}/batches/{batch_id}
curl "https://public-api.dapi.digital/v2/stocks/stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/batches/bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "id": "bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "stock_batch",
  "stock": {
    "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
    "object": "stock",
    "name": "Clicker 50 pack"
  },
  "region": {
    "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
    "object": "region",
    "name": "Western Europe"
  },
  "status": "in_production",
  "batches": 2,
  "units": {
    "purchased": 100,
    "made": 60,
    "used": 20,
    "available": 40
  },
  "price_paid": {
    "amount": 60000,
    "currency": "usd"
  },
  "unit_price": {
    "amount": 600,
    "currency": "usd"
  },
  "purchase_reference": "ST-8KD2X",
  "origin": "manual",
  "purchased_at": "2026-09-30T10:00:00Z",
  "completed_at": null
}

The stock purchase object

One checkout of stock batches.

Attributes

  • objectstring

    Names the type of this object. Always stock_purchase.

  • purchase_referencestring

    Reference shared by every batch bought in this checkout.

  • totalobject

    What was taken from your wallet.

  • batchesarray of StockBatch

    The batches bought, one per item.

The stock purchase object
{
  ,
  ,
  ,
  
}

Buy stock batches

POST/v2/stock-purchases

Credentials
An API key with the stocks:write scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
create_stock_purchase

Buys batches of one or more approved stocks in one checkout, paid from your wallet. There is no card top-up: if the balance is short, nothing is bought. Each item becomes a batch that the production partner of its region makes. Auto-reorder buys from the same wallet: when a region reaches its restock threshold and auto-reorder is on in your wallet settings, batches are bought automatically (origin: auto_reorder), so keep enough balance for both. Your plan must include prepaid stock. 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

  • itemsarray of objectRequired

    What to buy. Each stock and region pair at most once.

Returns201 Created

The purchase and the batches bought. Returns the stock purchase object.

Responses

  • 201

    The purchase and the batches bought.

  • 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).

  • 402

    Your wallet balance does not cover the purchase (insufficient_balance); details.required is the amount needed and details.balance what the wallet holds. Nothing was bought.

  • 403

    Your plan does not include prepaid stock (plan_limit_reached); details.fix_url points at upgrading.

  • 409

    A stock is not approved and priced (stock_not_approved); details.items lists the positions concerned.

  • 422

    A stock is not one of yours (stock_not_found), a region is not one of the stock regions (region_not_available), or a stock and region pair appears twice (duplicate_item); details.items lists the positions concerned.

  • 429

    Too many requests (rate_limited): the limit is 500 per minute per API key (or signed-in user), plus 60 per minute per API key (or signed-in user) for quote, upload, order and payment operations. 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/stock-purchases
curl -X POST "https://public-api.dapi.digital/v2/stock-purchases" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "stock": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "region": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "batches": 2
    }
  ]
}'
Response
{
  "object": "stock_purchase",
  "purchase_reference": "ST-8KD2X",
  "total": {
    "amount": 60000,
    "currency": "usd"
  },
  "batches": [
    {
      "id": "bat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "stock_batch",
      "stock": {
        "id": "stk_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "stock",
        "name": "Clicker 50 pack"
      },
      "region": {
        "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "region",
        "name": "Western Europe"
      },
      "status": "queued",
      "batches": 2,
      "units": {
        "purchased": 100,
        "made": 60,
        "used": 20,
        "available": 40
      },
      "price_paid": {
        "amount": 60000,
        "currency": "usd"
      },
      "unit_price": {
        "amount": 600,
        "currency": "usd"
      },
      "purchase_reference": "ST-8KD2X",
      "origin": "manual",
      "purchased_at": "2026-09-30T10:00:00Z",
      "completed_at": null
    }
  ]
}

The region object

A production region your stock is held in, and the countries it ships to. Orders use stock from a region that ships to the buyer.

Attributes

  • idstring

    Unique identifier of the region, prefixed with reg_. Treat it as an opaque string: store it and compare it, never parse it.

  • objectstring

    Names the type of this object. Always region.

  • namestring

    Display name, as set by the production partner.

  • countriesarray of string

    Countries orders can ship to from this region.

The region object
{
  ,
  ,
  ,
  
}

Get a production region

GET/v2/regions/{id}

Credentials
An API key with the stocks:read scope (full access includes every scope). A signed-in dashboard session works too.
For
Designers
Operation id
get_region

Returns a region one of your stocks is produced in, with the countries it ships to. Only regions of your own stocks are available. Designers only.

Path parameters

  • idstringRequired

    Unique identifier of the region, prefixed with reg_. Treat it as an opaque string: store it and compare it, never parse it.

Returns200 OK

The region. Returns the region object.

Responses

  • 200

    The region.

  • 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

    None of your stocks is produced in this region (region_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/regions/{id}
curl "https://public-api.dapi.digital/v2/regions/reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
Response
{
  "id": "reg_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "region",
  "name": "Western Europe",
  "countries": [
    "DE",
    "FR",
    "NL"
  ]
}