# Create organization API keys

> Create a key for your own systems to call the Commerce API, choose its scopes, and revoke it when it is no longer needed.

Source: https://docs.coritan.com/organizations/api-keys/

An organization API key lets your own systems call the [Commerce API](/organizations/storefront/commerce-api/) without a person signing in. The key belongs to one organization. Its scopes say what it may do, and you can cap how many requests it makes and where they come from.

A key works on the Commerce API only, at `https://api.coritan.com/api/v1/orgs/{org_slug}/commerce/...`, sent in the `X-API-Key` header. Every other organization route takes a member's access token instead.

## Before you begin

- You need the `owner` or `admin` role in the organization.
- Commerce must be turned on for the organization. Coritan turns it on, so ask [support](https://www.coritan.com/dashboard/support) if it is not. Until then, every Commerce API route answers `404` with the message `Commerce is not enabled for this organization.`
- Work out which scopes the key needs from the table below. Give it the fewest that do the job.

## Choose the scopes

A key reaches nothing in the Commerce API until you give it scopes. A `:write` scope includes the `:read` scope of the same area.

| Scope | What it opens |
| --- | --- |
| `commerce.store:read` | The store's settings, its publishable keys and its events. |
| `commerce.store:write` | Changing the store's settings, publishable keys, sales channels, regions, shipping profiles, zones and options, and fulfilment providers. |
| `commerce.catalog:read` | Products, tags, collections, categories, price lists, regions, shipping, stock locations, inventory items and sales channels, and your imports and their reports. |
| `commerce.catalog:write` | Changing products with their options, variants, prices and images; collections, categories and price lists; stock locations and inventory items; importing products from Shopify. |
| `commerce.inventory:write` | Setting stock levels, for one item or in a batch by SKU. |
| `commerce.customers:read` | Customers, customer groups and gift cards. |
| `commerce.customers:write` | Changing customers and customer groups. |
| `commerce.orders:read` | Orders with their documents and fulfilments, fulfilment providers with their deliveries and events, and returns with their reasons. |
| `commerce.orders:write` | Editing orders and adding notes. |
| `commerce.returns:write` | Creating, approving, rejecting, receiving and cancelling returns, and changing return reasons. |
| `commerce.refunds:write` | Refunding and cancelling orders, and refunding returns. |
| `commerce.promotions:write` | Promotions, reading them included, and issuing, changing and adjusting gift cards. |
| `commerce.fulfillment:write` | Creating fulfilments and marking them dispatched, shipped, delivered or cancelled. |
| `commerce.finance:read` | The balance and the ledger, disputes, payouts and tax reports. |
| `commerce.disputes:write` | Saving a dispute's evidence, sending it to the bank and accepting a dispute. |

Two wider forms exist. `commerce:*` grants every scope, and an area with `:*`, such as `commerce.orders:*`, grants every scope in that area. No key can manage the merchant profile, because it holds the owners' identities: an admin does that signed in. No key can ask for a payout either: an admin asks for one signed in.

## Create a key in the dashboard

1. Go to [Organizations](https://www.coritan.com/dashboard/organizations), open your organization and choose **Settings**.
2. In the **API keys** card, choose **New key…**.
3. Enter a **Label** of at least two characters that says what the key is for. The label is the only way to tell keys apart later.
4. Choose a **Rate limit**. The default is 4,000 requests an hour.
5. Optionally, fill in the **IP allow-list** with the addresses or CIDR ranges the key may be used from, such as `203.0.113.0/24`. Separate them with commas or new lines. We refuse requests from anywhere else.
6. Choose **Create key**, then copy the key from the dialog. It starts with `ct_`. We show it once and cannot show it again.

> [!WARNING]
> The form cannot set scopes yet, so a key made in the dashboard is refused by every Commerce API route. Create keys that need to work through the API, as [With the API](#with-the-api) shows. The dialog also tells you to send the key as a Bearer token; send it in the `X-API-Key` header instead.

## Revoke a key

1. In the **API keys** card, choose **Revoke…** on the key's row.
2. Type `revoke` and choose **Revoke key**.

The key stays in the table marked **Revoked**. You cannot turn it back on, so create a new key to replace it. Requests with the key can succeed for up to 10 seconds after you revoke it.

## Result

The table lists every key with its **Status**, **Rate limit** and the addresses it is **Allowed from**, or **Anywhere** when it has no allow-list. The **Last used** column shows `Never` for every key, because we do not record when a key is used yet. A key never appears in full again after the creation dialog closes.

## Troubleshooting

`401 Missing API key` or `401 Invalid API key`
: The request had no `X-API-Key` header, or the key is wrong or revoked. A key sent as `Authorization: Bearer` is not read at all.

`403 API key is not allowed from this address`
: The request came from an address outside the key's allow-list.

`403` with `scope_required`
: The key lacks the scope the route needs. The message names it, for example `This API key needs the commerce.orders:read scope.` Scopes cannot be changed on an existing key, so create a new key with the scopes it needs and revoke the old one.

`403` with `people_only`
: The route manages the merchant profile, which no key can reach. An admin has to do it signed in.

`403 Organization inactive`
: The organization is not active: it is pending, suspended, closed or deleted. Its keys work again only if it becomes active.

`404 Organization not found`
: The organization slug in the path is not the one the key belongs to.

`429 API key rate limit exceeded`
: The key made more requests in the last 60 minutes than its rate limit allows. Wait, or create a key with a higher limit.

## Related

- [Sell with the Commerce API](/organizations/storefront/commerce-api/)
- [Roles and permissions](/organizations/roles-and-permissions/)
- [Organization settings](/organizations/settings/)

## With the API

Managing keys takes an owner's or admin's access token, sent as `Authorization: Bearer $CORITAN_TOKEN`.

### Create a key with scopes

Send the scopes as a list under `permissions.scopes`:

```bash
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/api-keys" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"label": "Order sync", "permissions": {"scopes": ["commerce.orders:read", "commerce.fulfillment:write"]}, "rate_limit_per_hour": 4000, "ip_whitelist": ["203.0.113.0/24"]}'
```

| Field | Required | What it holds |
| --- | --- | --- |
| `label` | Yes | Up to 100 characters. |
| `permissions` | No | An object whose `scopes` list holds the key's scopes. Without it, the key has none. |
| `rate_limit_per_hour` | No | Requests allowed in any 60 minutes. Defaults to `4000`. |
| `ip_whitelist` | No | Addresses or CIDR ranges the key may be used from. Leave it out to allow any address. |

The answer is `201` with the key's `id`, `label`, `permissions`, `rate_limit_per_hour`, `ip_whitelist`, `is_active` and `created_at`, and the key itself in `raw_key`. Store `raw_key` now: no later answer contains it.

### Call the Commerce API with the key

```bash
curl "https://api.coritan.com/api/v1/orgs/acme/commerce/orders?limit=20" \
  -H "X-API-Key: $ORG_API_KEY"
```

### Routes

| Route | What it does |
| --- | --- |
| `GET /api/v1/orgs/{org_slug}/api-keys` | Lists every key, newest first, revoked ones included. |
| `POST /api/v1/orgs/{org_slug}/api-keys` | Creates a key and answers `201` with `raw_key`. |
| `DELETE /api/v1/orgs/{org_slug}/api-keys/{key_id}` | Revokes the key. Answers `404 API key not found` for a key another organization owns. |

No route changes a key once it exists.

## API

- `GET /api/v1/orgs/{org_slug}/api-keys`: List API keys (https://docs.coritan.com/api/reference/organizations/api-keys/#op-get-api-v1-orgs-org-slug-api-keys)
- `POST /api/v1/orgs/{org_slug}/api-keys`: Create API key (https://docs.coritan.com/api/reference/organizations/api-keys/#op-post-api-v1-orgs-org-slug-api-keys)
- `DELETE /api/v1/orgs/{org_slug}/api-keys/{key_id}`: Revoke API key (https://docs.coritan.com/api/reference/organizations/api-keys/#op-delete-api-v1-orgs-org-slug-api-keys-key-id)
