# Organization API: Commerce Store API

> Every Organization API operation tagged Commerce Store API.

Source: https://docs.coritan.com/api/reference/organizations/commerce-store-api/

Base URL: `https://api.coritan.com/api/v1`. Paths below are complete.

To try these requests in the browser, open the [interactive Organization API reference](https://api.coritan.com/docs/org).

## Operations

| Method | Path | Summary |
| --- | --- | --- |
| GET | [`/api/v1/orgs/{org_slug}/store`](#op-get-api-v1-orgs-org-slug-store) | Store info |
| POST | [`/api/v1/orgs/{org_slug}/store/carts`](#op-post-api-v1-orgs-org-slug-store-carts) | A cart in the key's mode and sales channel, in a region and its currency |
| GET | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}`](#op-get-api-v1-orgs-org-slug-store-carts-cart-id) | Get cart |
| PATCH | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}`](#op-patch-api-v1-orgs-org-slug-store-carts-cart-id) | Email, addresses, region or country (re-prices every line), note, locale, metadata |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/complete`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-complete) | Place the cart's order: {"order", "accesstoken"} |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/gift-cards`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-gift-cards) | Apply a gift card by its code: 10 attempts per 10 minutes per cart and per client IP |
| DELETE | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/gift-cards/{gift_card_id}`](#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-gift-cards-gift-card-id) | Remove gift card |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-line-items) | Add a variant; the same variant with the same metadata merges into its line |
| PATCH | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items/{line_id}`](#op-patch-api-v1-orgs-org-slug-store-carts-cart-id-line-items-line-id) | Set a line's quantity; 0 removes it |
| DELETE | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items/{line_id}`](#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-line-items-line-id) | Delete line item |
| GET | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/payment-providers`](#op-get-api-v1-orgs-org-slug-store-carts-cart-id-payment-providers) | The providers that can take this cart's payment, and whether it needs one |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/payment-sessions`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-payment-sessions) | Start the payment with provider, or refresh the one already started for the same amount |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/promotions`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-promotions) | Apply a code |
| DELETE | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/promotions`](#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-promotions) | Remove a code, named in the body {"code"} or as ?code= |
| POST | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/shipping-methods`](#op-post-api-v1-orgs-org-slug-store-carts-cart-id-shipping-methods) | Choose an option; it replaces the method its shipping profile had |
| GET | [`/api/v1/orgs/{org_slug}/store/carts/{cart_id}/shipping-options`](#op-get-api-v1-orgs-org-slug-store-carts-cart-id-shipping-options) | The options the cart's address and items allow, priced for them, per shipping profile |
| GET | [`/api/v1/orgs/{org_slug}/store/categories`](#op-get-api-v1-orgs-org-slug-store-categories) | The active, public categories as a tree |
| GET | [`/api/v1/orgs/{org_slug}/store/categories/{handle}`](#op-get-api-v1-orgs-org-slug-store-categories-handle) | Get category |
| GET | [`/api/v1/orgs/{org_slug}/store/collections`](#op-get-api-v1-orgs-org-slug-store-collections) | List collections |
| GET | [`/api/v1/orgs/{org_slug}/store/collections/{handle}`](#op-get-api-v1-orgs-org-slug-store-collections-handle) | A published collection; its products are /store/products?collectionhandle= |
| POST | [`/api/v1/orgs/{org_slug}/store/orders/lookup`](#op-post-api-v1-orgs-org-slug-store-orders-lookup) | Look up orders |
| GET | [`/api/v1/orgs/{org_slug}/store/orders/{order_id}`](#op-get-api-v1-orgs-org-slug-store-orders-order-id) | Get order |
| GET | [`/api/v1/orgs/{org_slug}/store/orders/{order_id}/documents`](#op-get-api-v1-orgs-org-slug-store-orders-order-id-documents) | The invoice and credit notes, as issued by the seller of record |
| GET | [`/api/v1/orgs/{org_slug}/store/orders/{order_id}/returns`](#op-get-api-v1-orgs-org-slug-store-orders-order-id-returns) | The order's returns, oldest first |
| POST | [`/api/v1/orgs/{org_slug}/store/orders/{order_id}/returns`](#op-post-api-v1-orgs-org-slug-store-orders-order-id-returns) | Request return |
| GET | [`/api/v1/orgs/{org_slug}/store/regions`](#op-get-api-v1-orgs-org-slug-store-regions) | The regions the store sells in, to pick a country and currency from |
| GET | [`/api/v1/orgs/{org_slug}/store/regions/{region_id}`](#op-get-api-v1-orgs-org-slug-store-regions-region-id) | Get region |
| GET | [`/api/v1/orgs/{org_slug}/store/return-reasons`](#op-get-api-v1-orgs-org-slug-store-return-reasons) | List return reasons |

### Store info {#op-get-api-v1-orgs-org-slug-store}

`GET /api/v1/orgs/{org_slug}/store`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### A cart in the key's mode and sales channel, in a region and its currency {#op-post-api-v1-orgs-org-slug-store-carts}

`POST /api/v1/orgs/{org_slug}/store/carts`

A cart in the key's mode and sales channel, in a region and its currency.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `region_id` | integer or null | no |
| `country_code` | string or null | no |
| `currency_code` | string or null | no |
| `email` | string or null | no |
| `sales_channel_id` | integer or null | no |
| `locale` | string or null | no |
| `metadata` | object or null | no |
| `items` | array of LineItemIn or null | no |
| `items[].variant_id` | integer | yes |
| `items[].quantity` | integer | no |
| `items[].metadata` | object or null | no |

#### Responses

| Status | Meaning |
| --- | --- |
| `201` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Get cart {#op-get-api-v1-orgs-org-slug-store-carts-cart-id}

`GET /api/v1/orgs/{org_slug}/store/carts/{cart_id}`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Email, addresses, region or country (re-prices every line), note, locale, metadata {#op-patch-api-v1-orgs-org-slug-store-carts-cart-id}

`PATCH /api/v1/orgs/{org_slug}/store/carts/{cart_id}`

Email, addresses, region or country (re-prices every line), note, locale, metadata.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `email` | string or null | no |
| `shipping_address` | object or null | no |
| `billing_address` | object or null | no |
| `region_id` | integer or null | no |
| `country_code` | string or null | no |
| `note` | string or null | no |
| `locale` | string or null | no |
| `metadata` | object or null | no |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Place the cart's order: {"order", "accesstoken"} {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-complete}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/complete`

Place the cart's order: ``{"order", "access_token"}``. The token is what
the shopper's order link carries (``GET /store/orders/{id}?token=``).

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |
| `Idempotency-Key` | header | string or null | no |

#### Request body

`application/json`

| Field | Type | Required |
| --- | --- | --- |
| `accept_terms` | boolean | no |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Apply a gift card by its code: 10 attempts per 10 minutes per cart and per client IP {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-gift-cards}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/gift-cards`

Apply a gift card by its code: 10 attempts per 10 minutes per cart and per client IP.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `code` | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Remove gift card {#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-gift-cards-gift-card-id}

`DELETE /api/v1/orgs/{org_slug}/store/carts/{cart_id}/gift-cards/{gift_card_id}`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `gift_card_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Add a variant; the same variant with the same metadata merges into its line {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-line-items}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items`

Add a variant; the same variant with the same metadata merges into its line.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `variant_id` | integer | yes |
| `quantity` | integer | no |
| `metadata` | object or null | no |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Set a line's quantity; 0 removes it {#op-patch-api-v1-orgs-org-slug-store-carts-cart-id-line-items-line-id}

`PATCH /api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items/{line_id}`

Set a line's quantity; 0 removes it.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `line_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `quantity` | integer | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Delete line item {#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-line-items-line-id}

`DELETE /api/v1/orgs/{org_slug}/store/carts/{cart_id}/line-items/{line_id}`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `line_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The providers that can take this cart's payment, and whether it needs one {#op-get-api-v1-orgs-org-slug-store-carts-cart-id-payment-providers}

`GET /api/v1/orgs/{org_slug}/store/carts/{cart_id}/payment-providers`

The providers that can take this cart's payment, and whether it needs one.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Start the payment with provider, or refresh the one already started for the same amount {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-payment-sessions}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/payment-sessions`

Start the payment with ``provider``, or refresh the one already started
for the same amount. ``accept_terms`` records the shopper's acceptance of
the store's terms with the session.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | yes | stripe, paypal or manual. |
| `accept_terms` | boolean | no |  |
| `return_url` | string or null | no |  |
| `cancel_url` | string or null | no |  |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Apply a code {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-promotions}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/promotions`

Apply a code. 422 ``promotion_not_applicable`` says why in ``reason``.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `code` | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Remove a code, named in the body {"code"} or as ?code= {#op-delete-api-v1-orgs-org-slug-store-carts-cart-id-promotions}

`DELETE /api/v1/orgs/{org_slug}/store/carts/{cart_id}/promotions`

Remove a code, named in the body ``{"code"}`` or as ``?code=``.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |
| `code` | query | string or null | no |

#### Request body

`application/json`

| Field | Type | Required |
| --- | --- | --- |
| `code` | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Choose an option; it replaces the method its shipping profile had {#op-post-api-v1-orgs-org-slug-store-carts-cart-id-shipping-methods}

`POST /api/v1/orgs/{org_slug}/store/carts/{cart_id}/shipping-methods`

Choose an option; it replaces the method its shipping profile had.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `option_id` | integer | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The options the cart's address and items allow, priced for them, per shipping profile {#op-get-api-v1-orgs-org-slug-store-carts-cart-id-shipping-options}

`GET /api/v1/orgs/{org_slug}/store/carts/{cart_id}/shipping-options`

The options the cart's address and items allow, priced for them, per shipping profile.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `cart_id` | path | string | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The active, public categories as a tree {#op-get-api-v1-orgs-org-slug-store-categories}

`GET /api/v1/orgs/{org_slug}/store/categories`

The active, public categories as a tree. A category that is inactive or
internal hides the categories under it too.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Get category {#op-get-api-v1-orgs-org-slug-store-categories-handle}

`GET /api/v1/orgs/{org_slug}/store/categories/{handle}`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `handle` | path | string | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### List collections {#op-get-api-v1-orgs-org-slug-store-collections}

`GET /api/v1/orgs/{org_slug}/store/collections`

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `org_slug` | path | string | yes |  |
| `limit` | query | integer | no | Default: `50`. |
| `offset` | query | integer | no | Default: `0`. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### A published collection; its products are /store/products?collectionhandle= {#op-get-api-v1-orgs-org-slug-store-collections-handle}

`GET /api/v1/orgs/{org_slug}/store/collections/{handle}`

A published collection; its products are ``/store/products?collection_handle=``.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `handle` | path | string | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Look up orders {#op-post-api-v1-orgs-org-slug-store-orders-lookup}

`POST /api/v1/orgs/{org_slug}/store/orders/lookup`

Email the links to the orders placed with ``email`` (in the key's mode,
within the store's order link lifetime). Always ``{"sent": true}``; the
email goes out after the answer, and only when there are orders.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | yes |  |
| `order_number` | string or null | no | #1001 or 1001: only that order. |

#### Responses

| Status | Meaning |
| --- | --- |
| `202` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Get order {#op-get-api-v1-orgs-org-slug-store-orders-order-id}

`GET /api/v1/orgs/{org_slug}/store/orders/{order_id}`

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `order_id` | path | string | yes |  |
| `org_slug` | path | string | yes |  |
| `token` | query | string or null | no | The order link's token. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The invoice and credit notes, as issued by the seller of record {#op-get-api-v1-orgs-org-slug-store-orders-order-id-documents}

`GET /api/v1/orgs/{org_slug}/store/orders/{order_id}/documents`

The invoice and credit notes, as issued by the seller of record.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `order_id` | path | string | yes |  |
| `org_slug` | path | string | yes |  |
| `token` | query | string or null | no | The order link's token. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The order's returns, oldest first {#op-get-api-v1-orgs-org-slug-store-orders-order-id-returns}

`GET /api/v1/orgs/{org_slug}/store/orders/{order_id}/returns`

The order's returns, oldest first.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `order_id` | path | string | yes |  |
| `org_slug` | path | string | yes |  |
| `token` | query | string or null | no | The order link's token. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Request return {#op-post-api-v1-orgs-org-slug-store-orders-order-id-returns}

`POST /api/v1/orgs/{org_slug}/store/orders/{order_id}/returns`

Ask to return shipped units, or to exchange them: ``requested`` until
the store approves or declines it.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `order_id` | path | string | yes |  |
| `org_slug` | path | string | yes |  |
| `token` | query | string or null | no | The order link's token. |
| `Idempotency-Key` | header | string or null | no |  |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of ReturnItemIn | yes |  |
| `items[].order_item_id` | integer | yes |  |
| `items[].quantity` | integer | yes |  |
| `items[].reason_code` | string or null | no | The code of a return reason. |
| `items[].note` | string or null | no |  |
| `exchange_items` | array of ExchangeItemIn or null | no |  |
| `exchange_items[].variant_id` | integer | yes |  |
| `exchange_items[].quantity` | integer | yes |  |
| `note` | string or null | no |  |

#### Responses

| Status | Meaning |
| --- | --- |
| `201` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### The regions the store sells in, to pick a country and currency from {#op-get-api-v1-orgs-org-slug-store-regions}

`GET /api/v1/orgs/{org_slug}/store/regions`

The regions the store sells in, to pick a country and currency from.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Get region {#op-get-api-v1-orgs-org-slug-store-regions-region-id}

`GET /api/v1/orgs/{org_slug}/store/regions/{region_id}`

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `region_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### List return reasons {#op-get-api-v1-orgs-org-slug-store-return-reasons}

`GET /api/v1/orgs/{org_slug}/store/return-reasons`

The reasons a shopper may pick for a return, in the store's order,
leaving out those it disabled. An item's ``reason_code`` takes a ``code``.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |
