# API endpoints (https://prood.com/docs/apps/api/endpoints)

All endpoints are prefixed with `/v1`. The interactive OpenAPI reference at [Commerce API](/docs/api) provides request/response schemas, try-it-out, and code samples.

## Health & identity [#health--identity]

| Method | Path | Scope | Description |
| --- | --- | --- | --- |
| GET | `/v1/health` | Public | Health check |
| GET | `/v1/me` | Storefront | Current caller: `organizationId`, `scopes` and `via` |
| GET | `/v1/openapi.json` | Public | OpenAPI 3.1 specification |

## Catalog (storefront) [#catalog-storefront]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/products` | List products (search, sort, pagination) |
| GET | `/v1/products/{id}` | Get product by ID |
| GET | `/v1/products/by-slug/{slug}` | Get product by URL slug |
| GET | `/v1/categories` | List categories |
| GET | `/v1/store` | Store info (name, currency, locales) |
| GET | `/v1/countries` | Country list for address forms |

Query parameters for `/v1/products`:

| Param | Type | Description |
| --- | --- | --- |
| `query` | string | Search term |
| `categoryId` | string | Filter by category |
| `sortField` | string | Field to sort by |
| `sortDirection` | `asc` or `desc` | Sort direction |
| `page` | number | Page number (default 1) |
| `perPage` | number | Items per page, up to 100 (default 20) |

## Cart (storefront) [#cart-storefront]

| Method | Path | Description |
| --- | --- | --- |
| POST | `/v1/carts` | Create a new cart |
| GET | `/v1/carts/{id}` | Get cart with items and totals |
| POST | `/v1/carts/{id}/items` | Add item to cart |
| PATCH | `/v1/carts/{id}/items/{itemId}` | Update item quantity |
| DELETE | `/v1/carts/{id}/items/{itemId}` | Remove item from cart |
| POST | `/v1/carts/{id}/coupon` | Apply coupon code. See the note below |
| DELETE | `/v1/carts/{id}/coupon` | Remove applied coupon |
| GET | `/v1/carts/{id}/shipping-methods` | List available shipping methods |
| PATCH | `/v1/carts/{id}/shipping-method` | Set shipping method |
| GET | `/v1/carts/{id}/payment-methods` | List available payment methods |
| PUT | `/v1/carts/{id}/shipping-address` | Set shipping address |
| PUT | `/v1/carts/{id}/billing-address` | Set billing address |
| POST | `/v1/carts/{id}/place-order` | Convert cart to order |

The coupon endpoints exist, but no merchant can create coupons yet, so there's nothing for a code to match.

## Orders (storefront) [#orders-storefront]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/orders` | List the signed-in customer's orders. An API key alone is refused |
| GET | `/v1/orders/{id}` | Get order. Staff and the customer who placed it see all of it; anyone else, the public view |

## Admin — Products [#admin--products]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/admin/products` | List all products |
| POST | `/v1/admin/products` | Create product |
| GET | `/v1/admin/products/{id}` | Get product |
| PATCH | `/v1/admin/products/{id}` | Update product |
| DELETE | `/v1/admin/products/{id}` | Delete product |

## Admin — Categories [#admin--categories]

| Method | Path | Description |
| --- | --- | --- |
| POST | `/v1/admin/categories` | Create category |
| PATCH | `/v1/admin/categories/{id}` | Update category |
| DELETE | `/v1/admin/categories/{id}` | Delete category |

## Admin — Orders [#admin--orders]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/admin/orders` | List all orders |
| GET | `/v1/admin/orders/{id}` | Get order detail |
| GET | `/v1/admin/orders/{id}/history` | Get order history |
| POST | `/v1/admin/orders/{id}/cancel` | Cancel order. Doesn't refund. On a paid order the shopper is told to contact the store. Use refund instead. |
| POST | `/v1/admin/orders/{id}/fulfill` | Mark order as fulfilled |
| POST | `/v1/admin/orders/{id}/refund` | Refund order in full |

## Admin — Customers [#admin--customers]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/admin/customers` | List customers |
| GET | `/v1/admin/customers/{id}` | Get customer detail |

## Admin — Store & inventory [#admin--store--inventory]

| Method | Path | Description |
| --- | --- | --- |
| GET | `/v1/admin/store` | Get store settings |
| PATCH | `/v1/admin/store` | Update store settings |
| POST | `/v1/admin/inventory` | Update inventory: `productId`, optional `variantId`, `quantity`, and optional `adjustment` (`set`, `increment` or `decrement`) |
| GET | `/v1/admin/dashboard` | Dashboard statistics |

## Webhooks [#webhooks]

| Method | Path | Auth | Description |
| --- | --- | --- | --- |
| POST | `/v1/webhooks/payments/{provider}` | `x-checkout-secret` | Process payment webhook |
| GET | `/v1/webhooks/payments/{provider}` | — | Provider verification challenge |

Query param: `org={orgId}` for tenant-scoped webhook verification.

## Response format [#response-format]

### Success [#success]

A single resource comes back as itself. A list comes back like this:

```json
{
  "items": [],
  "total": 42,
  "page": 1,
  "perPage": 20,
  "hasMore": true
}
```

### Error [#error]

```json
{
  "code": "NOT_FOUND",
  "message": "Product not found"
}
```

The HTTP status carries the status. A failed validation returns `422` with `code: "VALIDATION"` and an `errors` list, with a `path` and `message` for each field.

## Using the API client [#using-the-api-client]

```ts
import { createCommerceApiClient } from '@prood/api-client'

const api = createCommerceApiClient({
  baseUrl: 'http://localhost:3005/v1',
  headers: { 'x-api-key': 'pkAbC123...' },
})

const { data } = await api.GET('/products', {
  params: { query: { query: 'shirt', perPage: 10 } },
})
```

See [@prood/api-client](/docs/packages/api-client) for full client documentation.

## Related pages [#related-pages]

<Cards>
  <Card title="OpenAPI reference" href="/docs/api" description="Interactive documentation with schemas." />
  <Card title="Authentication" href="/docs/apps/api/authentication" description="Auth methods and scopes." />
  <Card title="MCP tools" href="/docs/apps/api/mcp" description="Same endpoints exposed as MCP tools." />
</Cards>
