Products API

Customer products are your own SKUs built on top of a base product — a base garment plus your designs, tags, and retail configuration. Each customer product is scoped to your account and invisible to other customers.

Base URL: https://developer.allthe.com/api/v1 Required scopes: products:read, products:write

Endpoints

| Method | Path | Scope | Status | | ------ | ------------------ | ---------------- | ------ | | GET | /products | products:read | Stable | | GET | /products/{id} | products:read | Stable | | POST | /products | products:write | Stable | | PATCH | /products/{id} | products:write | Stable | | DELETE | /products/{id} | products:write | Stable |

Products you create here behave exactly like ones built in the allthe customer portal: order them by id, and each line is decorated from the designs stored on the product.

Personalised products are portal-only. Products whose buyer fills in text or photos at checkout carry a template that only the builder can author. The API creates fixed-design products, and PATCH on a personalised product returns 409 conflict.


List products

GET /products

Lists all your non-archived customer products.

| Name | Type | Description | | -------- | ------- | ------------------------------------------------ | | limit | integer | Page size, 1–100. Default 25. | | cursor | string | Product id from previous next_cursor. |

curl "https://developer.allthe.com/api/v1/products?limit=5" \
  -H "Authorization: Bearer pat_live_..."
{
  "data": [
    {
      "id": "ckcp1...",
      "name": "Summer '26 Heavyweight Tee",
      "description": "Our signature heavyweight, new print for summer.",
      "status": "active",
      "tags": ["summer-26", "tees"],
      "retail_price": 34.00,
      "base_product": {
        "id": "ckl9...",
        "master_sku": "G6400-BLK",
        "title": "Gildan Softstyle T-Shirt"
      },
      "mockup_url": "https://cdn.allthe.com/mockups/summer26-tee.jpg",
      "print_areas": [
        { "print_area": "Front", "method": "DTG", "position": { "x": 0.5, "y": 0.5, "scale": 1, "rotation": 0 } }
      ],
      "variants": [
        { "id": "ckv1...", "blank_variant_sku": "G6400-BLK-M", "colour": "Black", "colour_hex": "#0A0A0A", "active": true }
      ],
      "created_at": "2026-03-10T09:00:00.000Z",
      "updated_at": "2026-04-02T14:23:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Fetch a product

GET /products/{id}

Returns one customer product in the same shape as the list response data[]. Returns 404 not_found if the product does not exist or belongs to another account.

mockup_url expires

Product images live in private storage, so mockup_url is a signed URL valid for one hour from the moment the response was generated. Render it or copy the bytes; don't persist the URL itself and expect it to work tomorrow — fetch the product again for a fresh one. It is null when the product has no mockup.


Create a product

POST /products

Builds a product on a base product from the catalogue. Artwork is supplied as URLs we fetch server-side — the same model as order intake, so you never upload file bytes to us.

| Field | Type | Required | Description | | --------------------- | -------- | -------- | --------------------------------------------------------------------------- | | base_product_id | string | Yes | Catalogue product id (see Catalog). | | name | string | Yes | Product name, max 200 chars. | | variant_skus | string[] | Yes | Blank variant SKUs to offer. Must belong to the base product and be active. | | description | string | No | Max 5000 chars. | | retail_price | number | No | Your retail price. Recorded for your own reporting; it does not affect what allthe charges you. | | tags | string[] | No | Up to 30 tags. | | mockup_url | string | No | Product image URL. Fetched and stored; becomes the line mock on orders. | | decoration.areas | array | No | Up to 10 { print_area, method, artwork_url, position? } — the designs printed on this product. | | status | string | No | active (default) or draft. |

position is optional per area: { x, y, scale, rotation }. x/y are fractions of the print area (0.5, 0.5 = centred, the default), scale is a multiplier, rotation is degrees.

curl -X POST "https://developer.allthe.com/api/v1/products" \
  -H "Authorization: Bearer pat_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "base_product_id": "ckl9...",
    "name": "Summer '\''26 Heavyweight Tee",
    "retail_price": 34.00,
    "tags": ["summer-26"],
    "variant_skus": ["G6400-BLK-M", "G6400-BLK-L"],
    "decoration": {
      "areas": [
        {
          "print_area": "Front",
          "method": "DTG",
          "artwork_url": "https://cdn.example.com/summer26-front.png"
        }
      ]
    }
  }'

Returns 201 with the product in the same shape as GET /products/{id}.

Validation is all-or-nothing. Every artwork URL is fetched and checked, and every SKU and (print_area × method) pair resolved, before anything is written. A single bad URL or unknown area returns 422 validation_failed and no product is created — a half-decorated product would look correct in the response and print wrong.

Artwork must pass the same checks as order intake — https only, public hosts, PNG/JPEG/WebP, size and dimension caps. See Artwork & decoration for the full table.

Re-using the same artwork is free. Designs are deduplicated by content: post the same bytes twice and the second product references the existing design rather than creating a new one. That also means you are not re-charged the one-off setup fee for artwork you have already printed.


Update a product

PATCH /products/{id}

Every field is optional; send only what you're changing. Accepts the same fields as create, except base_product_id — a product cannot be moved to a different base garment (create a new product instead).

curl -X PATCH "https://developer.allthe.com/api/v1/products/ckcp1..." \
  -H "Authorization: Bearer pat_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "retail_price": 36.00, "tags": ["summer-26", "restock"] }'

Two behaviours worth knowing:

  • decoration.areas replaces the decoration wholesale. The areas you send are the product's decoration afterwards; any area you omit is removed. This matches the builder — a partial merge would leave a stale area printing artwork you thought you had deleted.
  • variant_skus replaces the offered variants, but SKUs you drop are deactivated, not deleted, because placed orders still reference them. Re-sending a dropped SKU reactivates it.

Returns 404 not_found for a product that isn't yours, 409 conflict for an archived or personalised product.


Archive a product

DELETE /products/{id}

Returns 204 with no body. The product stops appearing in GET /products and can no longer be edited or ordered.

This is an archive, not a delete — placed orders reference the product for their artwork and naming, so the record is retained. The call is idempotent: archiving an already-archived product also returns 204.


Ordering a product you created

Pass the product id, a variant SKU, and the areas you want printed:

{
  "items": [
    {
      "product_id": "ckcp1...",
      "variant_sku": "G6400-BLK-M",
      "quantity": 2,
      "print_jobs": [{ "area": "Front", "method": "DTG" }]
    }
  ]
}

The artwork stored on the product is snapshotted onto the order line — you do not re-send artwork_url at order time.

Always send print_jobs listing every area you want printed. It is what the line is billed for, and it's how production enumerates the areas. Omitting it on a decorated product bills a single area, which will not match a multi-area product. Send print_jobs: [] only for a deliberately blank garment.

Use print_areas from the product to build print_jobs — not the base product's catalogue areas. GET /catalog/products/{id}/print-areas lists every area the garment supports; print_areas on the product lists the ones this product actually has artwork on. Ordering an area that isn't in print_areas returns 422 validation_failed, because it would bill you for decoration that doesn't exist and attach the wrong artwork.

See Orders for the full order body.