# Products

These are the products in **My products** in the portal: the products we sourced for you and the ones you added. The list has one item per variant (one SKU), including hidden products and products that can't be ordered right now. Use a product's `id` as `productId` in orders, shipments, reorder requests and SKU mappings.

A product has one of three kinds of price (`price.kind`): your agreed price, a reference price in Chinese yuan from our supplier before you have an agreed price, or none yet. A product can be restocked with a reorder request (`canReorder`) only when it has an agreed price and is available.

The list is sorted by when the product was added, newest first, then by SKU.

## List your products

`GET /v1/products`

Every product in My products, one item per variant, including hidden and unavailable ones. Newest added first, then by SKU.

| Property | Value |
|---|---|
| URL | `https://api.rephut.com/v1/products` |
| Permission | `catalog:read` |
| Access | Read: counts towards the read limit and works while your account is on hold |
| Idempotency-Key | Not used |
| Success | 200 OK |

### Query parameters

| Field | Type | Required | Description |
|---|---|---|---|
| `page` | integer | No | Page number. See [Pagination](https://docs.rephut.com/developers/pagination). From 1 to 10,000. Default: `1`. |

### Headers

| Header | Required | Value |
|---|---|---|
| `Authorization` | Yes | `Bearer <your API key>`. See [Authentication](https://docs.rephut.com/developers/authentication). |

### Response

`200` with `data`, a list of objects with the fields below (up to one page), and `meta` with `total`, `page`, `limit` and `pageCount`. See [Pagination](https://docs.rephut.com/developers/pagination).

| Field | Type | Description |
|---|---|---|
| `id` | string | Our product id. Use it as `productId` in orders, shipments, reorder requests and SKU mappings. |
| `sku` | string | Our SKU for this product variant. |
| `title` | string | Product name. |
| `variantLabel` | string | Name of this variant, for example its colour and size. |
| `customerSkus` | array of strings | Your SKUs mapped to this product. |
| `quoteCustomerSku` | string or null | Your SKU from the quote, when it is not already mapped. |
| `price` | object | AGREED: your agreed unit price. REFERENCE: the supplier's price before you have an agreed price. NONE: no price yet. |
| `price.kind` | string | Which price this is. See [Price kinds](#price-kinds). One of `AGREED`, `REFERENCE`, `NONE`. |
| `price.currency` | string | Only when `kind` is `AGREED`. Currency of the agreed price. Always `USD`. |
| `price.unitPriceCents` | integer | Only when `kind` is `AGREED`. Your agreed unit price in US cents. |
| `price.currency` | string | Only when `kind` is `REFERENCE`. Currency of the reference price. Always `CNY`. |
| `price.unitPriceCents` | integer | Only when `kind` is `REFERENCE`. Current supplier price in fen (1/100 CNY). |
| `price.approxUsdCents` | integer or null | Only when `kind` is `REFERENCE`. Rough USD equivalent; null when no exchange rate is set. |
| `price.checkedAt` | string (date-time) | Only when `kind` is `REFERENCE`. When we last checked the supplier's price. |
| `availableQty` | integer | Units of this product in our warehouse that are free to use (not set aside for orders or shipments). |
| `available` | boolean | `false` when the product can't be ordered right now; `inactiveReason` says why. |
| `inactiveReason` | string | Why the product is unavailable; empty when it is available or we gave no reason. |
| `hidden` | boolean | `true` when you hid the product in My products. Hidden products are still listed here. |
| `canReorder` | boolean | `true` when the product has an agreed price and is available, so you can restock it with [`POST /v1/requests/reorder`](https://docs.rephut.com/developers/reference/requests#ask-us-to-restock-products-at-your-agreed-prices). |
| `weightKnown` | boolean | `false` while we don't know the product's weight. Order shipping estimates then use an assumed weight; [`POST /v1/shipments/estimate`](https://docs.rephut.com/developers/reference/shipments#estimate-shipping-for-a-shipment-from-your-stock) counts the product as 0 g. |
| `addedAt` | string (date-time) | When the product was added to My products; for a product with an agreed price that was never added, when the agreed price took effect. |

### Errors

| Code | HTTP status | Meaning |
|---|---|---|
| `invalid_api_key` | 401 | The API key is missing, malformed, revoked or no longer valid. |
| `account_action_required` | 403 | Sign in to the portal and finish the required account steps first. |
| `api_not_enabled` | 403 | API access is not enabled for this account. |
| `insufficient_scope` | 403 | The API key does not have the permission this call needs. |
| `validation_failed` | 422 | The input is not valid. `details` lists each field and the reason. |
| `rate_limited` | 429 | Too many requests. Wait for the number of seconds in Retry-After. |
| `internal_error` | 500 | Unexpected error. Quote X-Request-Id when you contact support. |

Handle errors by `code`. See [Errors](https://docs.rephut.com/developers/errors).

```bash example=curl
curl 'https://api.rephut.com/v1/products?page=1' \
  -H "Authorization: Bearer $FULFILLBOT_API_KEY"
```

```js example=node
const response = await fetch("https://api.rephut.com/v1/products?page=1", {
  headers: {
    Authorization: `Bearer ${process.env.FULFILLBOT_API_KEY}`,
  },
});
const result = await response.json();
console.log(response.status, result);
```

```python example=python
import os

import requests

response = requests.get(
    "https://api.rephut.com/v1/products?page=1",
    headers={
        "Authorization": f"Bearer {os.environ['FULFILLBOT_API_KEY']}",
    },
    timeout=30,
)
print(response.status_code, response.json())
```

```json example=response status=200
{
  "success": true,
  "data": [
    {
      "id": "cm3p4r0d0002xyz7k2m9q8w2",
      "sku": "FB-10388-WHT",
      "title": "Ceramic mug 350 ml",
      "variantLabel": "White",
      "customerSkus": [],
      "quoteCustomerSku": "MUG-WHT",
      "price": {
        "kind": "REFERENCE",
        "currency": "CNY",
        "unitPriceCents": 1250,
        "approxUsdCents": 176,
        "checkedAt": "2026-11-01T06:00:00.000Z"
      },
      "availableQty": 0,
      "available": true,
      "inactiveReason": "",
      "hidden": false,
      "canReorder": false,
      "weightKnown": false,
      "addedAt": "2026-11-01T06:00:00.000Z"
    },
    {
      "id": "cm3p4r0d0001xyz7k2m9q8w1",
      "sku": "FB-10231-BLK-M",
      "title": "Cotton crew neck T-shirt",
      "variantLabel": "Black / M",
      "customerSkus": [
        "TEE-BLK-M"
      ],
      "quoteCustomerSku": null,
      "price": {
        "kind": "AGREED",
        "currency": "USD",
        "unitPriceCents": 385
      },
      "availableQty": 140,
      "available": true,
      "inactiveReason": "",
      "hidden": false,
      "canReorder": true,
      "weightKnown": true,
      "addedAt": "2026-10-20T03:00:00.000Z"
    }
  ],
  "meta": {
    "total": 2,
    "page": 1,
    "limit": 50,
    "pageCount": 1
  }
}
```

## Get one of your products

`GET /v1/products/{id}`

| Property | Value |
|---|---|
| URL | `https://api.rephut.com/v1/products/{id}` |
| Permission | `catalog:read` |
| Access | Read: counts towards the read limit and works while your account is on hold |
| Idempotency-Key | Not used |
| Success | 200 OK |

### Path parameters

| Name | Type | Description |
|---|---|---|
| `id` | string | Product id, from [`GET /v1/products`](https://docs.rephut.com/developers/reference/products#list-your-products). An id that doesn't exist, isn't yours or isn't a valid id returns 404 `not_found`. |

### Headers

| Header | Required | Value |
|---|---|---|
| `Authorization` | Yes | `Bearer <your API key>`. See [Authentication](https://docs.rephut.com/developers/authentication). |

### Response

`200` with `data`, an object with the fields below.

| Field | Type | Description |
|---|---|---|
| `id` | string | Our product id. Use it as `productId` in orders, shipments, reorder requests and SKU mappings. |
| `sku` | string | Our SKU for this product variant. |
| `title` | string | Product name. |
| `variantLabel` | string | Name of this variant, for example its colour and size. |
| `customerSkus` | array of strings | Your SKUs mapped to this product. |
| `quoteCustomerSku` | string or null | Your SKU from the quote, when it is not already mapped. |
| `price` | object | AGREED: your agreed unit price. REFERENCE: the supplier's price before you have an agreed price. NONE: no price yet. |
| `price.kind` | string | Which price this is. See [Price kinds](#price-kinds). One of `AGREED`, `REFERENCE`, `NONE`. |
| `price.currency` | string | Only when `kind` is `AGREED`. Currency of the agreed price. Always `USD`. |
| `price.unitPriceCents` | integer | Only when `kind` is `AGREED`. Your agreed unit price in US cents. |
| `price.currency` | string | Only when `kind` is `REFERENCE`. Currency of the reference price. Always `CNY`. |
| `price.unitPriceCents` | integer | Only when `kind` is `REFERENCE`. Current supplier price in fen (1/100 CNY). |
| `price.approxUsdCents` | integer or null | Only when `kind` is `REFERENCE`. Rough USD equivalent; null when no exchange rate is set. |
| `price.checkedAt` | string (date-time) | Only when `kind` is `REFERENCE`. When we last checked the supplier's price. |
| `availableQty` | integer | Units of this product in our warehouse that are free to use (not set aside for orders or shipments). |
| `available` | boolean | `false` when the product can't be ordered right now; `inactiveReason` says why. |
| `inactiveReason` | string | Why the product is unavailable; empty when it is available or we gave no reason. |
| `hidden` | boolean | `true` when you hid the product in My products. Hidden products are still listed here. |
| `canReorder` | boolean | `true` when the product has an agreed price and is available, so you can restock it with [`POST /v1/requests/reorder`](https://docs.rephut.com/developers/reference/requests#ask-us-to-restock-products-at-your-agreed-prices). |
| `weightKnown` | boolean | `false` while we don't know the product's weight. Order shipping estimates then use an assumed weight; [`POST /v1/shipments/estimate`](https://docs.rephut.com/developers/reference/shipments#estimate-shipping-for-a-shipment-from-your-stock) counts the product as 0 g. |
| `addedAt` | string (date-time) | When the product was added to My products; for a product with an agreed price that was never added, when the agreed price took effect. |

### Errors

| Code | HTTP status | Meaning |
|---|---|---|
| `invalid_api_key` | 401 | The API key is missing, malformed, revoked or no longer valid. |
| `account_action_required` | 403 | Sign in to the portal and finish the required account steps first. |
| `api_not_enabled` | 403 | API access is not enabled for this account. |
| `insufficient_scope` | 403 | The API key does not have the permission this call needs. |
| `not_found` | 404 | The resource does not exist or does not belong to this account. |
| `validation_failed` | 422 | The input is not valid. `details` lists each field and the reason. |
| `rate_limited` | 429 | Too many requests. Wait for the number of seconds in Retry-After. |
| `internal_error` | 500 | Unexpected error. Quote X-Request-Id when you contact support. |

Handle errors by `code`. See [Errors](https://docs.rephut.com/developers/errors).

```bash example=curl
curl 'https://api.rephut.com/v1/products/cm3p4r0d0001xyz7k2m9q8w1' \
  -H "Authorization: Bearer $FULFILLBOT_API_KEY"
```

```js example=node
const response = await fetch("https://api.rephut.com/v1/products/cm3p4r0d0001xyz7k2m9q8w1", {
  headers: {
    Authorization: `Bearer ${process.env.FULFILLBOT_API_KEY}`,
  },
});
const result = await response.json();
console.log(response.status, result);
```

```python example=python
import os

import requests

response = requests.get(
    "https://api.rephut.com/v1/products/cm3p4r0d0001xyz7k2m9q8w1",
    headers={
        "Authorization": f"Bearer {os.environ['FULFILLBOT_API_KEY']}",
    },
    timeout=30,
)
print(response.status_code, response.json())
```

```json example=response status=200
{
  "success": true,
  "data": {
    "id": "cm3p4r0d0001xyz7k2m9q8w1",
    "sku": "FB-10231-BLK-M",
    "title": "Cotton crew neck T-shirt",
    "variantLabel": "Black / M",
    "customerSkus": [
      "TEE-BLK-M"
    ],
    "quoteCustomerSku": null,
    "price": {
      "kind": "AGREED",
      "currency": "USD",
      "unitPriceCents": 385
    },
    "availableQty": 140,
    "available": true,
    "inactiveReason": "",
    "hidden": false,
    "canReorder": true,
    "weightKnown": true,
    "addedAt": "2026-10-20T03:00:00.000Z"
  }
}
```

## Price kinds

| Value | Meaning |
|---|---|
| `AGREED` | Your agreed unit price in US cents. |
| `REFERENCE` | The supplier's current price in fen (CNY), before you have an agreed price, with a rough USD equivalent. |
| `NONE` | No price yet. |
