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

# Create buyer instructions

> Add a new scoped buyer-instructions row

`POST /api/v2/storefront/buyer-instructions`

Creates a new buyer-instructions row. The `(operatorDomain, brandDomain)` tuple
is unique per storefront — a duplicate scope fails with `409`. To change an
existing row, [update](/v2/storefront/buyer-instructions/tasks/update-buyer-instructions)
it instead.

## Request

```bash curl theme={null}
curl -X POST https://api.apostra.com/api/v2/storefront/buyer-instructions \
  -H "Authorization: Bearer $SCOPE3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operatorDomain": "acme-media.com",
    "brandDomain": "northwind.example",
    "discountPercent": 15,
    "notes": "Brand requires Acme Media viewability ≥ 70%.",
    "countries": ["US", "CA"]
  }'
```

## Parameters

All five fields are required. Send `null` for any you want to leave unscoped.

| Field | Type | Required | Notes |
| - | - | - | - |
| `operatorDomain` | string \| null | Yes | Operator the row applies to, or `null` for any operator. 1–253 chars |
| `brandDomain` | string \| null | Yes | Brand the row applies to, or `null` for any brand. 1–253 chars |
| `discountPercent` | number \| null | Yes | Discount off base price, `0`–`100`. `null` for no discount |
| `notes` | string \| null | Yes | Composition notes, max 2000 chars. `null` for no notes |
| `countries` | string\[] \| null | Yes | ISO 3166-1 alpha-2 codes (uppercase), at least one when set. `null` for all countries |

## Response

```json theme={null}
{
  "id": "18",
  "storefrontId": "1234",
  "operatorDomain": "acme-media.com",
  "brandDomain": "northwind.example",
  "discountPercent": 15,
  "notes": "Brand requires Acme Media viewability ≥ 70%.",
  "countries": ["US", "CA"],
  "createdAt": "2026-06-06T15:00:00.000Z",
  "updatedAt": "2026-06-06T15:00:00.000Z",
  "createdBy": "operator@touchline.example"
}
```

Returns `201` with the created row. The resolver picks the maximum
`discountPercent` across all rows that match a given buyer.

## Errors

* `400 VALIDATION_ERROR` — missing required field, `discountPercent` out of
  `0`–`100`, or a malformed country code.
* `409 CONFLICT` — a row already exists for this `(operatorDomain, brandDomain)`
  scope. Update that row instead.
* `401 UNAUTHORIZED` — missing or invalid bearer token.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Buyer instruction tasks" href="/v2/storefront/buyer-instructions/tasks" icon="list-check">
    All buyer-instructions operations.
  </Card>

  <Card title="Update buyer instructions" href="/v2/storefront/buyer-instructions/tasks/update-buyer-instructions" icon="pen">
    Change discount, notes, or countries.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.