# Create a product (POST /v1/catalog/products)

> POST /v1/catalog/products: Create a product. border.bot API reference (Catalogue).

Source: https://border.bot/docs/api/create-catalog-product

> Documentation index: https://border.bot/llms.txt. Every page is Markdown at its URL + `.md`.

`POST https://api.border.bot/v1/catalog/products`

Requires an API key (`Authorization: Bearer bb_live_…`).

A product with its items (each SKU unique in your catalogue), content components, source and any codes you already hold. Codes are checked against the vocabularies (`GET /catalog/terms`). Free.

API key scope: `catalog`.

## Request body (JSON)

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | yes |  |
| `description` | string \| null | no |  |
| `brand` | string \| null | no |  |
| `manufacturerName` | string \| null | no |  |
| `manufacturerCountry` | string \| null | no |  |
| `category` | string \| null | no |  |
| `materialSummary` | string \| null | no |  |
| `tags` | string[] | no |  |
| `imageUrls` | string[] | no |  |
| `productUrl` | string \| null | no |  |
| `slug` | string \| null | no |  |
| `originCountry` | string \| null | no |  |
| `originBasis` | string \| null | no |  |
| `originEvidence` | object \| null | no |  |
| `preferentialClaims` | object[] | no |  |
| `attributes` | object[] | no |  |
| `markets` | array \| null | no |  |
| `quantityUnit` | string \| null | no |  |
| `supplementaryUnits` | object[] | no |  |
| `extra` | object | no |  |
| `status` | "draft" \| "active" | no |  |
| `sku` | string \| null | no |  |
| `gtin` | string \| null | no |  |
| `mpn` | string \| null | no |  |
| `unitValue` | number \| null | no |  |
| `currency` | string \| null | no |  |
| `weight` | number \| null | no |  |
| `weightUnit` | "kg" \| "g" \| "lb" \| "oz" \| null | no |  |
| `items` | object[] | no |  |
| `components` | object[] | no |  |
| `source` | object | no |  |
| `codes` | object[] | no |  |

## Responses

- `200`: The product. (`CatalogProductResponse`)
- `400`: Invalid input (`invalid_input`). (`Error`)
- `401`: Missing, invalid, revoked or expired API key (`unauthorized`). (`Error`)
- `403`: The API key doesn’t have the `catalog` scope (`forbidden`, `details.reason: "missing_scope"`). (`Error`)
- `409`: A SKU is already used by another product (`conflict`, `details.reason: "sku_taken"`). (`Error`)
- `429`: Rate limited (`rate_limited`). Retry after `Retry-After` seconds; `RateLimit` says which limit was hit (`r=0`, `t` seconds until its window ends) and `RateLimit-Policy` its quota. (`Error`)
- `500`: Unexpected error (`internal`). (`Error`)

## Example

```bash
curl -X POST 'https://api.border.bot/v1/catalog/products' \
  -H 'Authorization: Bearer bb_live_...' \
  -H 'Content-Type: application/json' \
  -d '{"title":"Stainless steel water bottle 750 ml","brand":"Acme","materialSummary":"stainless steel body, polypropylene lid","originCountry":"CN","markets":["US","GB","DE"],"sku":"BOTTLE-750","unitValue":20,"currency":"USD","weight":350,"weightUnit":"g","components":[{"material":"steel","weight":300,"weightUnit":"g","value":6,"currency":"USD","origins":[{"kind":"melt_pour","country":"US"}]},{"material":"plastic","weight":50,"weightUnit":"g"}],"source":{"kind":"api","externalIds":{"id":"erp-10023"}}}'
```
