> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyparrow.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Products

> Create and manage products, variants, stock, and delivery options with the Hyparrow API.

## Overview

A **product** is anything you sell through Hyparrow — physical goods that ship, or digital
items delivered by file. Each product carries a name, description, price, currency, and an
optional category and SKU.

Products can be enriched with three building blocks:

* **Variants** — sellable versions of the same product (e.g. *Small / Medium / Large*), each
  with its own price, SKU, stock, tax, and discount.
* **Stock** — the quantity available, tracked at the product level and, when you use variants,
  per variant.
* **Delivery options** — the shipping or fulfilment choices a buyer sees at checkout
  (`free`, `standard`, `fast`, `premium`), each with a price and an estimated delivery window.

All product endpoints live under the base URL and are authenticated with your API key pair.

<Note>
  **Base URL:** `https://api.hyparrow.cloud/api/v1`

  Every request must include both auth headers:

  ```
  X-API-Key: pk_live_xxxxxxxxxxxx
  X-API-Secret: sk_live_xxxxxxxxxxxx
  ```

  To test against the sandbox, use `https://sandbox.hyparrow.cloud/api/v1` with your
  `pk_test_` / `sk_test_` keys. No real money or stock is affected.
</Note>

<Note>
  Money fields in product payloads are expressed in **naira** as decimal strings
  (for example `"4500.00"`). Where the wider Hyparrow API settles money in transactions, amounts
  are in **kobo** (1 naira = 100 kobo). Keep this distinction in mind when reconciling product
  prices against payment webhooks.
</Note>

## Create a product

<Steps>
  <Step title="Build the payload">
    Decide whether the product is `physical` or `digital`, set a positive `price`, and
    optionally attach `variants` inline. A digital product typically carries a `fileUrl`.
  </Step>

  <Step title="POST to /products/">
    Send the request with your auth headers. A successful call returns `201 Created` with the
    full product record, including its generated `id` and non-expiring payment `slug`.
  </Step>

  <Step title="Enrich it">
    Add images, delivery options, or extra variants in follow-up calls.
  </Step>
</Steps>

### Request

```bash theme={null}
curl -X POST https://api.hyparrow.cloud/api/v1/products/ \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Classic Cotton Tee",
    "description": "100% combed cotton crew-neck",
    "type": "physical",
    "price": "4500.00",
    "currency": "NGN",
    "stock": 120,
    "sku": "TEE-CLASSIC",
    "category": "Apparel",
    "isActive": true,
    "variants": [
      { "name": "Small",  "sku": "TEE-S", "price": "4500.00", "stockQty": 40 },
      { "name": "Medium", "sku": "TEE-M", "price": "4500.00", "stockQty": 50 },
      { "name": "Large",  "sku": "TEE-L", "price": "5000.00", "stockQty": 30 }
    ]
  }'
```

### Response

```json theme={null}
{
  "success": true,
  "message": "Product created successfully",
  "data": {
    "id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
    "userId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "name": "Classic Cotton Tee",
    "description": "100% combed cotton crew-neck",
    "category": "Apparel",
    "sku": "TEE-CLASSIC",
    "type": "physical",
    "status": "active",
    "price": "4500.00",
    "currency": "NGN",
    "taxType": "none",
    "discountType": "none",
    "isActive": true,
    "stockQuantity": 120,
    "stockStatus": "in_stock",
    "slug": "classic-cotton-tee-8f1c2d3e",
    "deliveryOptions": [],
    "createdAt": "2026-06-30T10:14:22Z",
    "updatedAt": "2026-06-30T10:14:22Z"
  }
}
```

<Warning>
  `type` must be `physical` or `digital`, `price` must be greater than `0`, and if you send
  `stock` it must be greater than `0`. Each inline variant must have a non-empty `name` and a
  positive `price`, otherwise the request fails with `400` and a message such as
  `variants[1].price must be greater than 0`.
</Warning>

## List products

`GET /products/` returns the authenticated client's products with pagination and filters.

| Query param   | Description                         |
| ------------- | ----------------------------------- |
| `page`        | Page number (default `1`)           |
| `limit`       | Items per page (default `20`)       |
| `type`        | `physical` or `digital`             |
| `category`    | Filter by category string           |
| `status`      | `active`, `inactive`, or `archived` |
| `from` / `to` | Date range, `YYYY-MM-DD`            |

```bash theme={null}
curl "https://api.hyparrow.cloud/api/v1/products/?type=physical&limit=10" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
```

```json theme={null}
{
  "success": true,
  "data": [
    { "id": "8f1c2d3e-...", "name": "Classic Cotton Tee", "price": "4500.00", "status": "active" }
  ],
  "total": 1
}
```

## Search products

`GET /products/search` performs a keyword and price-range search across your catalogue.

| Query param             | Description                                      |
| ----------------------- | ------------------------------------------------ |
| `q`                     | Free-text query matched against name/description |
| `category`              | Restrict to a category                           |
| `minPrice` / `maxPrice` | Inclusive price bounds (naira)                   |

```bash theme={null}
curl "https://api.hyparrow.cloud/api/v1/products/search?q=cotton&minPrice=1000&maxPrice=8000" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
```

```json theme={null}
{
  "success": true,
  "data": [
    { "id": "8f1c2d3e-...", "name": "Classic Cotton Tee", "price": "4500.00" }
  ]
}
```

## Get a single product

`GET /products/{productId}` returns the full product, including variants and delivery options.

```bash theme={null}
curl https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
```

A missing or malformed ID returns `404` / `400` respectively.

## Update a product

`PUT /products/{productId}` updates any subset of fields. Only the fields you send are changed.

<Note>
  Stock can be supplied as either `stock` or the alias `stockQuantity`. If both are present,
  `stock` wins.
</Note>

```bash theme={null}
curl -X PUT https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "price": "4900.00", "isActive": true }'
```

```json theme={null}
{
  "success": true,
  "message": "Product updated successfully",
  "data": { "id": "8f1c2d3e-...", "price": "4900.00", "isActive": true }
}
```

## Delete a product

`DELETE /products/{productId}` removes the product.

```bash theme={null}
curl -X DELETE https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
```

```json theme={null}
{ "success": true, "message": "Product deleted successfully" }
```

## Calculate price

`GET /products/{productId}/price` computes the total for a given quantity and optional variant,
applying any tax and discount.

| Query param | Description                       |
| ----------- | --------------------------------- |
| `variantId` | Optional variant to price against |
| `quantity`  | Units to price (defaults to 1)    |

```bash theme={null}
curl "https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../price?quantity=3&variantId=2b1a..." \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
```

```json theme={null}
{ "success": true, "data": { "totalPrice": "15000.00" } }
```

## Variants

Variants let one product carry multiple sellable versions, each with its own price, SKU, stock,
tax, and discount.

<CodeGroup>
  ```bash List variants theme={null}
  curl https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../variants \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
  ```

  ```bash Add a variant theme={null}
  curl -X POST https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../variants \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "X-Large",
      "sku": "TEE-XL",
      "price": "5200.00",
      "stockQty": 25,
      "taxType": "none",
      "discountType": "none"
    }'
  ```

  ```bash Update a variant theme={null}
  curl -X PUT https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../variants/2b1a... \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{ "price": "5400.00" }'
  ```

  ```bash Delete a variant theme={null}
  curl -X DELETE https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../variants/2b1a... \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
  ```
</CodeGroup>

Adding a variant returns `201` with the created record:

```json theme={null}
{
  "success": true,
  "data": {
    "id": "2b1a9c8d-...",
    "productId": "8f1c2d3e-...",
    "name": "X-Large",
    "sku": "TEE-XL",
    "price": "5200.00",
    "stockQty": 25,
    "taxType": "none",
    "discountType": "none"
  }
}
```

## Stock

Stock is managed separately from price so you can adjust inventory without touching the rest of
the product.

* **Product stock** — `PATCH /products/{productId}/stock`
* **Variant stock** — `PATCH /products/{productId}/variants/{variantId}/stock`

Both accept the same body:

```bash theme={null}
curl -X PATCH https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../stock \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "quantity": 200 }'
```

```json theme={null}
{ "success": true, "message": "Product stock updated" }
```

```bash theme={null}
curl -X PATCH https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../variants/2b1a.../stock \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "quantity": 60 }'
```

```json theme={null}
{ "success": true, "message": "Variant stock updated" }
```

## Delivery options

Delivery options are the fulfilment choices presented to buyers. Each option has a `type`
(`free`, `standard`, `fast`, or `premium`), a `label`, a `price`, an `estimatedDays` window, and
an `isActive` flag.

<CodeGroup>
  ```bash List options theme={null}
  curl https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../delivery-options \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
  ```

  ```bash Add an option theme={null}
  curl -X POST https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../delivery-options \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "standard",
      "label": "Standard delivery (Lagos)",
      "price": "1500.00",
      "estimatedDays": "2-4 days",
      "isActive": true
    }'
  ```

  ```bash Update an option theme={null}
  curl -X PUT https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../delivery-options/d3f4... \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{ "price": "1800.00", "estimatedDays": "1-3 days" }'
  ```

  ```bash Delete an option theme={null}
  curl -X DELETE https://api.hyparrow.cloud/api/v1/products/8f1c2d3e-.../delivery-options/d3f4... \
    -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
    -H "X-API-Secret: sk_live_xxxxxxxxxxxx"
  ```
</CodeGroup>

Adding an option returns `201`:

```json theme={null}
{
  "success": true,
  "data": {
    "id": "d3f4a5b6-...",
    "productId": "8f1c2d3e-...",
    "type": "standard",
    "label": "Standard delivery (Lagos)",
    "price": "1500.00",
    "estimatedDays": "2-4 days",
    "isActive": true
  }
}
```

<Warning>
  An invalid delivery `type` returns `400` with `invalid delivery type, must be
      free/standard/fast/premium`.
</Warning>
