# Integrator orders

Orders integrators place for their own customers, paid from the wallet or through a hosted checkout. Integrators only.

## Endpoints

-   [GET `/v2/integrator/orders`](https://public-api.dapi.digital/docs/reference/integrator-orders.md#list_integrator_orders)
-   [POST `/v2/integrator/orders`](https://public-api.dapi.digital/docs/reference/integrator-orders.md#create_integrator_order)
-   [POST `/v2/integrator/orders/shipping-estimate`](https://public-api.dapi.digital/docs/reference/integrator-orders.md#estimate_integrator_order_shipping)
-   [GET `/v2/integrator/orders/{id}`](https://public-api.dapi.digital/docs/reference/integrator-orders.md#get_integrator_order)
-   [POST `/v2/integrator/orders/{id}/cancel`](https://public-api.dapi.digital/docs/reference/integrator-orders.md#cancel_integrator_order)

## The integrator order object

An order for prints of your quotes: what was ordered, where it ships, its status, what was charged and, in `checkout` mode, what you earn.

### Attributes

-   `id` (string): Unique identifier of the order, prefixed with `ord_`. Treat it as an opaque string: store it and compare it, never parse it.
-   `object` (string): Names the type of this object. Always `order`.
-   `number` (string): Human-readable order number, the one your customers and 3DAPI support use.
-   `channel` (string): Which money flow the order follows.
    
    Possible values: `integrator_checkout`, `integrator_wallet`.
    
-   `status` (OrderStatus):
    
    Where the order is:
    
    -   `awaiting_payment`: you still have to pay for it.
    -   `paid`: paid, waiting to be assigned to a production partner.
    -   `assigned`: a production partner has it; production has not started.
    -   `in_production`: being made.
    -   `shipped`: on its way to the customer. `shipping` has the tracking details.
    -   `completed`: delivered and settled.
    -   `on_hold`: there is not enough stock to fulfil it.
    -   `rejected`: the production partner refused it.
    -   `returned`: sent back after shipping.
    -   `cancelled`: cancelled, usually after a full refund.
    
-   `customer` (OrderCustomer or null): Who ordered. Personal data: null unless the API key has the `orders:read_customer` scope.
    -   `name` (string): Customer full name.
    -   `email` (string or null): Customer email.
    -   `phone` (string or null): Customer phone.
    -   `company` (object or null): Set when the buyer bought as a business.
        -   `name` (string or null): Company name.
        -   `tax_id` (string or null): VAT or tax number the buyer entered.
        -   `tax_id_validated` (boolean or null): True when VIES confirmed the EU VAT number, so the sale was zero-rated. False when it did not. Null when not applicable.
-   `shipping_address` (OrderShippingAddress): Where the order ships. The country is always shown because it decides shipping and VAT; the rest is personal data.
    -   `formatted` (string or null): The full address as one line. Null without the `orders:read_customer` scope.
    -   `city` (string or null): City. Null without the `orders:read_customer` scope.
    -   `country` (string or null): Country name. Always present when known.
    -   `country_code` (string or null): ISO 3166-1 alpha-2 country code. Always present when known.
-   `charges` (OrderCharges): What the payer was charged for the order.
    -   `paid_by` (string): `buyer` when a customer paid 3DAPI (storefront orders), `you` when you paid for the order (manual, imported and API orders, and replacements you were responsible for), `dapi` when 3DAPI covers it (a replacement for a production partner mistake; you were not charged, and the charges show what the replacement cost). `earnings` is null unless `buyer`.
    -   `items` (object): Items total.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `shipping` (object): Shipping charged.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `vat` (object): VAT on the order. Zero outside the EU and UK.
        -   `amount` (object): VAT charged.
            -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
            -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
        -   `rate` (number): VAT rate as a fraction, for example 0.21. 0 when none.
            
            Range 0 to 1.
            
        -   `included` (boolean): True when VAT is carved out of the prices; false when it was added on top.
        -   `country` (string or null): Country whose rate applied, ISO alpha-2. Null when none.
    -   `sample_credit` (object or null): Sample credit that covered part of the charge. Null when none was used.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `total` (object): The full charge, VAT included, before any sample credit.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
-   `earnings` (OrderEarnings or null): What you earn from a buyer-paid order and what was taken off it. Null when you paid for the order yourself.
    -   `manufacturing` (object): Paid to the production partner for this order. 0 on an order fulfilled from prepaid stock: that manufacturing was paid when you bought the stock batch.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `platform_fee` (object): 3DAPI commission, at your plan rate.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `payment_processing` (object): Card processing fee taken from your earnings on the buyer payment. Kept by the card processor even when the order is refunded. 0 on older orders whose payout was made without deducting it.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `refunded` (object): What completed refunds took off your earnings.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `net` (object): What you keep. Never rounded up to 0: minimum prices include the card fee, so it is not negative on sales made at or above them, but a price set before that rule can show a negative amount here.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
-   `shipping` (OrderShipping): Shipping details.
    -   `tier` (string or null): Shipping tier the order was priced at, frozen at placement: `small`, `medium` or `large`, the weight bands a variant's `shipping.tier` describes. Null when it was priced at the flat rate.
    -   `carrier` (string or null): Carrier, once shipped.
    -   `tracking_number` (string or null): Tracking number, once shipped.
    -   `shipped_at` (timestamp or null): When the order shipped. Null before shipping, and for some orders that shipped before this was recorded.
-   `customer_notes` (string or null): Notes the customer left at checkout. Null without the `orders:read_customer` scope, since buyers often write personal details here.
-   `created_at` (timestamp): Point in time, ISO 8601 in UTC.
-   `updated_at` (timestamp): Point in time, ISO 8601 in UTC.
-   `mode` (string): `wallet`: you pay the production price plus shipping from your wallet (a shortfall is charged to your saved card). `checkout`: your customer pays the sales price you set through a hosted 3DAPI checkout and you earn the difference.
-   `checkout` (object or null): The hosted checkout link in `checkout` mode, null in `wallet` mode.
    -   `object` (string): Names the type of this object. Always `checkout_link`.
    -   `url` (string): Send your customer here to pay.
    -   `status` (string): `open` until paid or closed; `completed` once the buyer paid; `expired` when the link timed out unpaid, which cancels the order (`checkout.expired`); `cancelled` when you cancelled the unpaid order (`order.cancelled`).
    -   `expires_at` (timestamp): Point in time, ISO 8601 in UTC.
-   `item_count` (integer): Units ordered across all lines.
    
    Range at least 0.
    
-   `items` (array of IntegratorOrderItem, optional): The order lines. In lists only present with `expand[]=items`.
    -   `id` (string): Unique identifier of the order item, prefixed with `itm_`. Treat it as an opaque string: store it and compare it, never parse it.
    -   `object` (string): Names the type of this object. Always `order_item`.
    -   `quote` (object): The quote this line prints, as named when ordered.
        -   `id` (string): Unique identifier of the quote, prefixed with `qte_`. Treat it as an opaque string: store it and compare it, never parse it.
        -   `object` (string): Names the type of this object. Always `quote`.
        -   `name` (string): Display name of the quote.
    -   `materials` (array of CatalogMaterialReference): The materials loaded, in slot order. `material_slots` says which slot each one goes in.
        -   `id` (string): Unique identifier of the material, prefixed with `mat_`. Treat it as an opaque string: store it and compare it, never parse it.
        -   `object` (string): Names the type of this object. Always `material`.
        -   `name` (string): Display name of the material.
    -   `material_slots` (array of MaterialSlot): Which material goes in which extruder slot, by slot. Slots the file does not use are left out.
        -   `slot` (integer): Extruder slot (filament number) in the 3MF, from 1, as `suggested_materials[].slot` on the quote lists them.
            
            Range 1 to 16.
            
        -   `material` (CatalogMaterialReference): Same shape as `CatalogMaterialReference` above.
    -   `quantity` (integer): Copies of the quote printed on this line.
        
        Range at least 1.
        
    -   `unit_price` (object): What the payer paid per unit: the production price in `wallet` mode, your sales price in `checkout` mode.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `production_unit_price` (object): The quote price per unit at this quantity (it falls as a plate fills), plus the price of the extras shipped with each unit: what you pay in `wallet` mode, your cost in `checkout` mode. It already includes the platform fee: `earnings.manufacturing` plus `earnings.platform_fee` equal this price times the quantity, summed over the lines.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `extras` (array of object): Extras shipped with every unit of this line, as ordered. Empty when none.
        -   `extra` (ExtraReference): Reference to a extra. Pass the matching `expand[]` path to receive the full extra instead.
            -   `id` (string): Unique identifier of the extra, prefixed with `xtr_`. Treat it as an opaque string: store it and compare it, never parse it.
            -   `object` (string): Names the type of this object. Always `extra`.
            -   `name` (string): Display name of the extra.
        -   `quantity_per_unit` (integer): How many of this extra ship with each printed unit of the line.
            
            Range at least 1.
            
    -   `total` (object): `unit_price` times `quantity`.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
-   `refunds` (array of object): Completed refunds, oldest first, in lists too. Empty when none.
    -   `id` (string): Unique identifier of the refund, prefixed with `rfd_`. Treat it as an opaque string: store it and compare it, never parse it.
    -   `amount` (object): Total refunded, VAT included.
        -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `created_at` (timestamp): Point in time, ISO 8601 in UTC.
-   `reference` (string or null): Your own order id, as you sent it.

**The integrator order object**

```json
{
  "id": "ord_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
  "object": "order",
  "number": "2AP7K2M9X",
  "channel": "integrator_wallet",
  "status": "paid",
  "customer": {
    "name": "Ana Popescu",
    "email": "ana@example.com",
    "phone": null,
    "company": null
  },
  "shipping_address": {
    "formatted": "Str. Test 1, Cluj, RO",
    "city": "Cluj",
    "country": "Romania",
    "country_code": "RO"
  },
  "charges": {
    "paid_by": "you",
    "items": {
      "amount": 5000,
      "currency": "usd"
    },
    "shipping": {
      "amount": 800,
      "currency": "usd"
    },
    "vat": {
      "amount": {
        "amount": 0,
        "currency": "usd"
      },
      "rate": 0,
      "included": false,
      "country": null
    },
    "sample_credit": null,
    "total": {
      "amount": 5800,
      "currency": "usd"
    }
  },
  "earnings": null,
  "shipping": {
    "tier": "small",
    "carrier": null,
    "tracking_number": null,
    "shipped_at": null
  },
  "customer_notes": null,
  "created_at": "2026-10-09T08:39:29Z",
  "updated_at": "2026-10-09T08:40:02Z",
  "item_count": 10,
  "mode": "wallet",
  "checkout": null,
  "items": [
    {
      "id": "itm_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "object": "order_item",
      "quote": {
        "id": "qte_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "quote",
        "name": "phone-stand.stl"
      },
      "materials": [
        {
          "id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
          "object": "material",
          "name": "PLA Black"
        }
      ],
      "material_slots": [
        {
          "slot": 1,
          "material": {
            "id": "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
            "object": "material",
            "name": "PLA Black"
          }
        }
      ],
      "quantity": 10,
      "unit_price": {
        "amount": 500,
        "currency": "usd"
      },
      "production_unit_price": {
        "amount": 500,
        "currency": "usd"
      },
      "extras": [],
      "total": {
        "amount": 5000,
        "currency": "usd"
      }
    }
  ],
  "refunds": [],
  "reference": "SHOP-1042"
}
```

## List your orders

GET `/v2/integrator/orders`

- **Credentials**: An API key with the `orders:read` scope (full access includes every scope). A signed-in dashboard session works too.

- **For**: Integrators

- **Operation id**: `list_integrator_orders`

Your orders, newest first, without their lines unless `expand[]=items`. Integrators only.

### Query parameters

-   `status` (array of OrderStatus): Only orders in these statuses (repeatable). Same shape as `OrderStatus` above.
-   `mode` (string): `wallet`: you pay the production price plus shipping from your wallet (a shortfall is charged to your saved card). `checkout`: your customer pays the sales price you set through a hosted 3DAPI checkout and you earn the difference.
-   `created_after` (timestamp): Only orders placed after this time.
-   `created_before` (timestamp): Only orders placed before this time.
-   `reference` (string): Exact match on your own order id.
-   `quote` (string): Only orders with a line from this quote.
-   `search` (string): Part of the order `number` or of your `reference`, case-insensitive. For example `7K2M` finds `2AP7K2M9X`, and `1042` finds `SHOP-1042`.
-   `expand[]` (array of string): `items` adds the order lines.
-   `limit` (integer): How many results per page, from 1 to 100.
    
    Range 1 to 100. Defaults to 20.
    
-   `cursor` (string): Where to continue from: the `next_cursor` of the previous page. Omit for the first page.

### Returns 200 OK

A page of orders.

Response attributes (IntegratorOrderList):

-   `object` (string): Names the type of this object. Always `list`.
-   `data` (array of IntegratorOrder): The page of results.
    
    Described in [the integrator order object](https://public-api.dapi.digital/docs/reference/integrator-orders.md#integrator_order_object).
    
-   `has_more` (boolean): True when more results exist after this page. Fetch them by passing `next_cursor` as `cursor`.
-   `next_cursor` (string or null): Opaque cursor for the next page, or null on the last page. Pass it back unchanged as `cursor`.

### Responses

-   `200`: A page of orders.
-   `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](https://public-api.dapi.digital/docs/guides/errors.md#error-object).

**Request**

```bash
curl "https://public-api.dapi.digital/v2/integrator/orders" \
  -H "x-api-key: $DAPI_API_KEY"
```

**Response 200**

```json
{
  "object": "list",
  "data": [
    [
      {
        "id": "ord_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
        "object": "order",
        "number": "2AP7K2M9X",
        "channel": "integrator_wallet",
        "status": "paid",
        "customer": {
          "name": "Ana Popescu",
          "email": "ana@example.com",
          "phone": null,
          "company": null
        },
        "shipping_address": {
          "formatted": "Str. Test 1, Cluj, RO",
          "city": "Cluj",
          "country": "Romania",
          "country_code": "RO"
        },
        "charges": {
          "paid_by": "you",
          "items": {
            "amount": 5000,
            "currency": "usd"
          },
          "shipping": {
            "amount": 800,
            "currency": "usd"
          },
          "vat": {
            "amount": {
              "amount": 0,
              "currency": "usd"
            },
            "rate": 0,
            "included": false,
            "country": null
          },
          "sample_credit": null,
          "total": {
            "amount": 5800,
            "currency": "usd"
          }
        },
        "earnings": null,
        "shipping": {
          "tier": "small",
          "carrier": null,
          "tracking_number": null,
          "shipped_at": null
        },
        "customer_notes": null,
        "created_at": "2026-10-09T08:39:29Z",
        "updated_at": "2026-10-09T08:40:02Z",
        "item_count": 10,
        "mode": "wallet",
        "checkout": null,
        "refunds": [],
        "reference": "SHOP-1042"
      }
    ]
  ],
  "has_more": false,
  "next_cursor": null
}
```

## Order prints of your quotes

POST `/v2/integrator/orders`

- **Credentials**: An API key with the `orders:write` scope (full access includes every scope). A signed-in dashboard session works too.

- **For**: Integrators

- **Operation id**: `create_integrator_order`

Orders prints of your own `ready` quotes once your account is approved. In `wallet` mode you pay the production price plus shipping from your wallet; a shortfall is charged to your saved card with VAT on the top-up, as for every wallet top-up. The order comes back paid, numbered `2AP...`, and goes to production. If payment fails, no order is created. In `checkout` mode your customer pays your `unit_sales_price` plus shipping, and VAT when they ship to the EU or UK, on a hosted 3DAPI checkout: the order comes back `awaiting_payment`, numbered `2AC...`, with `checkout.url` to send them to, and `order.created` is sent. The link stays open 24 hours; unpaid, the order is then cancelled and `checkout.expired` is sent. Cancelling it yourself before it is paid sends `order.cancelled` instead. Once the order is completed you earn the sales price less the production price and the card fee, credited to your wallet. A line may carry approved extras (`items[].extras`): their price per unit is added to the line's production price in both modes. Integrators only.

### Headers

-   `Idempotency-Key` (string): 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

-   `mode` (string, required): `wallet`: you pay the production price plus shipping from your wallet (a shortfall is charged to your saved card). `checkout`: your customer pays the sales price you set through a hosted 3DAPI checkout and you earn the difference.
-   `items` (array of object, required): What to print and ship, 1 to 100 lines.
    -   `quote` (string, required): One of your quotes with status `ready`.
    -   `quantity` (integer, required): Copies of this quote to print and ship, 1 to 10000 per line (an order has up to 100 lines). The production price per unit depends on it. Designer orders (create\_order) allow 1 to 1000 units per line instead, also with up to 100 lines.
        
        Range 1 to 10000.
        
    -   `materials` (one of): Which catalog material (list\_materials) goes in which extruder slot of the quote's file. Either a list of `{ slot, material }`, one for each slot in the quote's `suggested_materials` and no others, or a plain list of material ids for slots 1, 2, 3... in order, which only works when the quote uses slots from 1 without gaps. Slots that do not match are refused with `material_slots_mismatch` (`details.expected_slots`). Send this or `use_suggested_materials`, not both. Quotes without `suggested_materials` (created before suggestions) take materials for slots 1 to n, n no more than the quote prints with (`material_not_allowed`, `details.slots`).
        -   Shape **array**:
            
        -   Shape **array**:
            
    -   `use_suggested_materials` (boolean): Print with the quote's `suggested_materials`: the catalog material closest to each filament colour in your file, in the slot it uses. Send this or `materials`, not both. Refused with `suggestions_unavailable` when the quote has no suggestions.
    -   `unit_sales_price` (object or null): Required in `checkout` mode, forbidden in `wallet` mode: what your customer pays per unit, net of VAT, in `usd` (another currency is refused with `currency_not_supported`). Not below the minimum, which covers the production unit price (the quote price plus the extras on this line) and this unit's share of the card fee checkout takes, so a sale at the minimum never loses money. With k = fee percent / 100 x (1 + the VAT rate the buyer pays on top) and the fee of the destination (EU 1.5% + $0.30, UK 2.5% + $0.30, elsewhere 2.9% + $0.30): minimum = (production\_unit\_price + (k x shipping + $0.30) / units in the order) / (1 - k), rounded up to the cent. A lower price is refused with `sales_price_below_production`, with `details.minimum`, `details.production_unit_price` and `details.formula`.
        -   `amount` (integer, required): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
        -   `currency` (string, required): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.
    -   `extras` (array of object): Bought-in parts shipped with every unit of this line, for example magnets or screws. Each extra's approved `price` times `quantity_per_unit` is added to the production price of every unit: you pay it in `wallet` mode, and in `checkout` mode it raises the minimum `unit_sales_price` and comes out of your earnings. They also count toward the parcel's shipping weight, as on designer orders. The production partner gets them with the order.
        -   `extra` (string, required): One of your extras, approved by 3DAPI (list\_extras).
        -   `quantity_per_unit` (integer, required): How many of the extra ship with each unit.
            
            Range 1 to 100.
            
-   `shipping_address` (object, required): Where to ship, in both modes. In `checkout` mode it also decides the buyer's VAT (EU and UK consumers pay their country's rate on top) and the payment account.
    -   `line1` (string, required): Street and number.
    -   `line2` (string or null): Apartment, suite, floor or building. Omit or send null when there is none.
    -   `city` (string, required): City or town.
    -   `state` (string or null): State, province, county or region, where the address uses one. Omit or send null otherwise.
    -   `postal_code` (string or null): Postal or ZIP code. Omit or send null where the country has none.
    -   `country_code` (string, required): ISO 3166-1 alpha-2, uppercase. A code that is not a real country is refused with `validation_failed`.
-   `customer` (object, required): Who receives the order. In `checkout` mode this is your customer, who gets the order confirmation and shipping emails from 3DAPI naming you as the seller.
    -   `name` (string, required): Full name of the person receiving the order.
    -   `email` (string, required): Email of the person receiving the order.
    -   `phone` (string or null): Phone number with country prefix. Omit or send null when you have none.
    -   `company` (object or null): `checkout` mode only: set when your customer buys as a business. Returned as `customer.company`, with `tax_id_validated` once VIES has checked the number.
        -   `name` (string, required): The business name, printed on the invoice.
        -   `tax_id` (string or null): The business VAT number. For an EU shipping country it is checked with VIES when the order is created: a confirmed number pays no VAT (reverse charge), a number VIES rejects is refused (`vat_number_invalid`), and when VIES cannot be reached VAT is charged. Numbers for other countries, the UK included, are not checked and VAT follows the normal rules.
-   `checkout` (object or null): Required in `checkout` mode, forbidden in `wallet` mode.
    -   `success_url` (string, required): Where the hosted page sends your customer after paying. Must be https; plain http is accepted only for localhost and 127.0.0.1. Anything else is refused with `validation_failed`.
    -   `cancel_url` (string, required): Where the hosted page sends your customer if they leave without paying. Same rules as `success_url`.
-   `reference` (string or null): Your own order id, for matching.
-   `customer_notes` (string or null): Free-text notes for the order, up to 2000 characters. Returned as `customer_notes`, which is only shown to keys with the `orders:read_customer` scope.
-   `use_sample_credit` (boolean): `wallet` mode only (forbidden in `checkout` mode): spend your sample credit on this order before the wallet balance. It applies only when the order ships to your own country (your billing or sign-up country); otherwise the order is placed at full price. What applied is shown in `charges.sample_credit`. Default false.

### Returns 201 Created

The order: paid in \`wallet\` mode, \`awaiting\_payment\` with its checkout link in \`checkout\` mode. Returns [the integrator order object](https://public-api.dapi.digital/docs/reference/integrator-orders.md#integrator_order_object).

### Responses

-   `201`: The order: paid in `wallet` mode, `awaiting_payment` with its checkout link in `checkout` mode.
-   `400`: The request is invalid (`validation_failed`).
-   `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`: Payment failed: the card was declined (`payment_failed`), or the wallet is short and there is no saved card (`insufficient_balance`). No order was created.
-   `403`: Your account cannot order yet: add your business billing details, or, to sell to EU or UK customers from outside the EU and UK, an active EU responsible person (`compliance_blocked`, `details.requirements`; `details.fix_url` links to the dashboard page that fixes it).
-   `404`: A quote is not one of yours (`quote_not_found`).
-   `409`: Production is paused (`production_unavailable`).
-   `422`: A quote is not ready (`quote_not_ready`) or was rejected in review (`quote_rejected`), an extra is not one of yours (`extra_not_found`) or not approved (`extra_not_approved`), your account is not approved yet (`quote_not_approved`), a material is unknown or there are more materials than the quote prints with (`material_not_allowed`), the slots sent are not the slots the quote's file uses (`material_slots_mismatch`, `details.expected_slots`), the suggested materials were asked for on a quote that has none (`suggestions_unavailable`), a sales price is not in usd (`currency_not_supported`) or is below the minimum (`sales_price_below_production`, `details.minimum`), we do not deliver to the country (`shipping_destination_not_served`: 3DAPI does not deliver to Russia, Belarus, Iran or Syria), or VIES did not confirm the business buyer's EU VAT number (`vat_number_invalid`, `details.tax_id` and `details.country_code`; nothing is created). The request is checked in full before the account compliance gate (403), so these come first.
-   `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`.
-   `503`: Card payments are not available right now (`card_payments_unavailable`); no order was created.

Errors use [the error object](https://public-api.dapi.digital/docs/guides/errors.md#error-object).

**Request**

```bash
curl -X POST "https://public-api.dapi.digital/v2/integrator/orders" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "wallet",
  "items": [
    {
      "quote": "qte_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "quantity": 10,
      "materials": [
        "mat_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu"
      ]
    }
  ],
  "shipping_address": {
    "line1": "Hauptstrasse 12",
    "city": "Berlin",
    "postal_code": "10115",
    "country_code": "DE"
  },
  "customer": {
    "name": "Jane Buyer",
    "email": "jane@example.com"
  },
  "reference": "SHOP-1042"
}'
```

## Estimate the shipping of an order

POST `/v2/integrator/orders/shipping-estimate`

- **Credentials**: An API key with the `orders:read` scope (full access includes every scope). A signed-in dashboard session works too.

- **For**: Integrators

- **Operation id**: `estimate_integrator_order_shipping`

What `create_integrator_order` would charge for shipping these lines to this country, computed by the same code the order is charged with: the parcel takes the tier of its heaviest item, every other item (extra-small ones excluded) adds the zone's per-item price, and extras count toward the weight. Nothing is created, and your account does not need to be approved yet.

The total is without VAT: in `checkout` mode, buyers in the EU or UK pay VAT on top. It can change if the rate card changes before you order; the order charges the rate card at the time it is placed.

Send the same `items` (quote, quantity, extras) and the destination you would order with. Integrators only.

### Headers

-   `Idempotency-Key` (string): 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

-   `country` (string, required): Destination country, ISO 3166-1 alpha-2, uppercase: the `shipping_address.country_code` you would order with. A code that is not a real country is refused with `validation_failed`.
-   `items` (array of object, required): The lines of the order you would place, as `create_integrator_order` takes them. Materials and prices do not change shipping, so they are not sent.
    -   `quote` (string, required): One of your quotes with status `ready`.
    -   `quantity` (integer, required): Copies of this quote to print and ship, 1 to 10000 per line (an order has up to 100 lines). The production price per unit depends on it. Designer orders (create\_order) allow 1 to 1000 units per line instead, also with up to 100 lines.
        
        Range 1 to 10000.
        
    -   `extras` (array of object): The extras you would ship with every unit of this line, as on `create_integrator_order`. They count toward the shipping weight.
        -   `extra` (string, required): One of your extras, approved by 3DAPI (list\_extras).
        -   `quantity_per_unit` (integer, required): How many of the extra ship with each unit.
            
            Range 1 to 100.
            

### Returns 200 OK

The shipping the order would be charged.

Response attributes (ShippingEstimate):

-   `object` (string): Names the type of this object. Always `shipping_estimate`.
-   `country_code` (string): Destination country, as sent.
-   `zone` (object or null): The zone that serves the country. Null when the order cannot be weighed yet and the flat rate applies.
    -   `code` (string): Stable identifier of the zone, for example `eu-core`. Zones are platform configuration, so they have a readable code instead of an opaque id.
    -   `name` (string): Display name of the zone.
-   `tier` (string or null): Tier of the heaviest item in the parcel, which the parcel is priced at. Null with the flat rate.
    
    Possible values: `small`, `medium`, `large`.
    
-   `additional_items` (integer): Items charged on top of the heaviest one. Extra-small items ship free and are not counted.
    
    Range at least 0.
    
-   `total` (object): What the order would be charged for shipping, without VAT. In `checkout` mode buyers in the EU or UK pay VAT on top.
    -   `amount` (integer): Amount in the smallest currency unit (cents for usd). 5000 means $50.00. Never a decimal.
    -   `currency` (string): Three-letter ISO 4217 currency code, lowercase. Every amount is `usd` today.

### Responses

-   `200`: The shipping the order would be charged.
-   `400`: The request is invalid (`validation_failed`).
-   `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`: A quote is not one of yours (`quote_not_found`).
-   `422`: A quote is not ready (`quote_not_ready`) or was rejected in review (`quote_rejected`), an extra is not one of yours (`extra_not_found`) or not approved (`extra_not_approved`), or we do not deliver to the country (`shipping_destination_not_served`: 3DAPI does not deliver to Russia, Belarus, Iran or Syria).
-   `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](https://public-api.dapi.digital/docs/guides/errors.md#error-object).

**Request**

```bash
curl -X POST "https://public-api.dapi.digital/v2/integrator/orders/shipping-estimate" \
  -H "x-api-key: $DAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "country": "DE",
  "items": [
    {
      "quote": "qte_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "quantity": 2
    },
    {
      "quote": "qte_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
      "quantity": 2,
      "extras": [
        {
          "extra": "xtr_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu",
          "quantity_per_unit": 1
        }
      ]
    }
  ]
}'
```

**Response 200**

```json
{
  "object": "shipping_estimate",
  "country_code": "DE",
  "zone": {
    "code": "eu-core",
    "name": "EU Core"
  },
  "tier": "medium",
  "additional_items": 3,
  "total": {
    "amount": 1099,
    "currency": "usd"
  }
}
```

## Get an order

GET `/v2/integrator/orders/{id}`

- **Credentials**: An API key with the `orders:read` scope (full access includes every scope). A signed-in dashboard session works too.

- **For**: Integrators

- **Operation id**: `get_integrator_order`

One of your orders, with its lines and refunds. Integrators only.

### Path parameters

-   `id` (string, required): Unique identifier of the order, prefixed with `ord_`. Treat it as an opaque string: store it and compare it, never parse it.

### Returns 200 OK

The order. Returns [the integrator order object](https://public-api.dapi.digital/docs/reference/integrator-orders.md#integrator_order_object).

### Responses

-   `200`: The order.
-   `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 order with this id (`order_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](https://public-api.dapi.digital/docs/guides/errors.md#error-object).

**Request**

```bash
curl "https://public-api.dapi.digital/v2/integrator/orders/ord_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu" \
  -H "x-api-key: $DAPI_API_KEY"
```

## Cancel an order

POST `/v2/integrator/orders/{id}/cancel`

- **Credentials**: An API key with the `orders:write` scope (full access includes every scope). A signed-in dashboard session works too.

- **For**: Integrators

- **Operation id**: `cancel_integrator_order`

Cancels an order. An unpaid `checkout` order (`awaiting_payment`) has its link closed and is cancelled. A `paid` order a production partner has not started is refunded in full: to your wallet for `wallet` orders, to your customer's card for `checkout` orders. Integrators only.

### Path parameters

-   `id` (string, required): Unique identifier of the order, prefixed with `ord_`. Treat it as an opaque string: store it and compare it, never parse it.

### Headers

-   `Idempotency-Key` (string): 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.

### Returns 200 OK

The order, cancelled. Returns [the integrator order object](https://public-api.dapi.digital/docs/reference/integrator-orders.md#integrator_order_object).

### Responses

-   `200`: The order, cancelled.
-   `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 order with this id (`order_not_found`).
-   `409`: The order cannot be cancelled (`order_not_cancellable`): it is already cancelled, or past `paid` (a production partner started it; contact support). Unpaid checkout orders (`awaiting_payment`) and `paid` orders can be cancelled; the message says which case applies.
-   `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](https://public-api.dapi.digital/docs/guides/errors.md#error-object).

**Request**

```bash
curl -X POST "https://public-api.dapi.digital/v2/integrator/orders/ord_bfP0GSqKoZFrD72H5Os0rc7HV9XP6eQJu/cancel" \
  -H "x-api-key: $DAPI_API_KEY"
```

---

3DAPI API Docs. This page on the web: https://public-api.dapi.digital/docs/reference/integrator-orders. Index of every page: https://public-api.dapi.digital/docs/llms.txt.
