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

# Products API — create a product catalog

> Create and manage your product catalog. Products represent the goods or services you sell and can be attached to invoices and checkout links.

The products API lets you build a catalog of the goods and services you sell. Once you create a product, you can reference it by ID when adding line items to invoices or building checkout links — saving you from re-entering details each time. Products support physical goods, digital downloads, and services, with optional tax and discount configuration. All routes require authentication.

## Product object

<ResponseField name="id" type="string">
  Unique product identifier (UUID).
</ResponseField>

<ResponseField name="name" type="string">
  Product name.
</ResponseField>

<ResponseField name="description" type="string">
  Optional description of the product (up to 2,000 characters).
</ResponseField>

<ResponseField name="type" type="string">
  Product type. One of `physical`, `digital`, or `service`.
</ResponseField>

<ResponseField name="price" type="number">
  Unit price in the product's currency.
</ResponseField>

<ResponseField name="currency" type="string">
  Currency of the price. One of `NGN` or `USD`. Defaults to your account's default currency.
</ResponseField>

<ResponseField name="status" type="string">
  One of `active`, `inactive`, or `archived`. Only `active` products can be used in new invoices and checkout links.
</ResponseField>

<ResponseField name="stock_quantity" type="number">
  Optional stock count. `null` means unlimited stock.
</ResponseField>

<ResponseField name="image_urls" type="array">
  Up to 10 image URLs associated with this product.
</ResponseField>

<ResponseField name="tax_type" type="string">
  How tax is applied: `none`, `percentage`, or `fixed`.
</ResponseField>

<ResponseField name="tax_rate" type="number">
  Tax amount. Interpreted as a percentage when `tax_type` is `percentage`, or as a fixed currency amount when `fixed`.
</ResponseField>

<ResponseField name="discount_type" type="string">
  How discounts are applied: `none`, `percentage`, or `fixed`.
</ResponseField>

<ResponseField name="discount" type="number">
  Discount amount. Interpreted as a percentage or fixed amount depending on `discount_type`.
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 creation timestamp.
</ResponseField>

<ResponseField name="updated_at" type="string">
  ISO 8601 last-updated timestamp.
</ResponseField>

***

## Create a product

```
POST /products
```

### Request body

<ParamField body="name" type="string" required>
  Product name. Maximum 255 characters.
</ParamField>

<ParamField body="description" type="string">
  Optional product description. Maximum 2,000 characters.
</ParamField>

<ParamField body="type" type="string">
  Product type: `physical`, `digital`, or `service`.
</ParamField>

<ParamField body="price" type="number" required>
  Unit price. Must be a positive number.
</ParamField>

<ParamField body="currency" type="string">
  `NGN` or `USD`. Defaults to your account currency.
</ParamField>

<ParamField body="stock_quantity" type="number">
  Stock count. Omit for unlimited stock.
</ParamField>

<ParamField body="image_urls" type="array">
  Array of image URLs. Maximum 10 items.
</ParamField>

<ParamField body="tax_type" type="string">
  `none`, `percentage`, or `fixed`. Defaults to `none`.
</ParamField>

<ParamField body="tax_rate" type="number">
  Tax amount. Required when `tax_type` is not `none`.
</ParamField>

<ParamField body="discount_type" type="string">
  `none`, `percentage`, or `fixed`. Defaults to `none`.
</ParamField>

<ParamField body="discount" type="number">
  Discount amount. Required when `discount_type` is not `none`.
</ParamField>

### Example

```bash theme={null}
curl -X POST https://api.dubupay.com/api/v1/products \
  -H "X-Api-Key: dubu_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Annual SaaS Subscription",
    "description": "Access to all premium features for one year.",
    "type": "digital",
    "price": 120000,
    "currency": "NGN"
  }'
```

Returns `201 Created` with the new product object.

***

## List products

```
GET /products
```

Returns a paginated list of your products.

### Query parameters

<ParamField query="status" type="string">
  Filter by status: `active`, `inactive`, or `archived`.
</ParamField>

<ParamField query="search" type="string">
  Full-text search across product names.
</ParamField>

<ParamField query="page" type="number">
  Page number (1-indexed). Defaults to `1`.
</ParamField>

<ParamField query="limit" type="number">
  Results per page. Maximum `100`.
</ParamField>

### Example

```bash theme={null}
curl "https://api.dubupay.com/api/v1/products?status=active&page=1&limit=20" \
  -H "X-Api-Key: dubu_sk_live_YOUR_API_KEY"
```

***

## Get a product

```
GET /products/:id
```

Retrieve a single product by its UUID.

### Path parameters

<ParamField path="id" type="string" required>
  UUID of the product.
</ParamField>

### Example

```bash theme={null}
curl https://api.dubupay.com/api/v1/products/prod_uuid_here \
  -H "X-Api-Key: dubu_sk_live_YOUR_API_KEY"
```

***

## Update a product

```
PATCH /products/:id
```

Update one or more fields on an existing product. Only the fields you include in the request body are modified.

### Path parameters

<ParamField path="id" type="string" required>
  UUID of the product to update.
</ParamField>

### Request body

All fields are optional. You can update `status` to `archived` to retire a product without deleting it.

<ParamField body="name" type="string">
  New product name.
</ParamField>

<ParamField body="description" type="string">
  New description. Pass `null` to clear it.
</ParamField>

<ParamField body="type" type="string">
  `physical`, `digital`, or `service`.
</ParamField>

<ParamField body="status" type="string">
  `active`, `inactive`, or `archived`.
</ParamField>

<ParamField body="price" type="number">
  New unit price.
</ParamField>

<ParamField body="currency" type="string">
  `NGN` or `USD`.
</ParamField>

<ParamField body="stock_quantity" type="number">
  Updated stock count. Pass `null` for unlimited.
</ParamField>

### Example

```bash theme={null}
curl -X PATCH https://api.dubupay.com/api/v1/products/prod_uuid_here \
  -H "X-Api-Key: dubu_sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "inactive"}'
```

***

## Delete a product

```
DELETE /products/:id
```

Permanently deletes a product. This action cannot be undone. Consider setting `status` to `archived` instead if you want to retain historical data.

### Path parameters

<ParamField path="id" type="string" required>
  UUID of the product to delete.
</ParamField>

### Example

```bash theme={null}
curl -X DELETE https://api.dubupay.com/api/v1/products/prod_uuid_here \
  -H "X-Api-Key: dubu_sk_live_YOUR_API_KEY"
```

Returns `200 OK` on success.
