---
title: "API authentication and keys"
description: "Create an API key from Settings > Developers > API Keys, find your store_id, secure your keys and troubleshoot authentication errors."
url: https://help.getkanal.com/en/articles/14-api-authentication-and-keys
collection: "API"
updated: 2026-10-21
language: en
alternates: [fr-fr]
---

# API authentication and keys

Create an API key from Settings > Developers > API Keys, find your store_id, secure your keys and troubleshoot authentication errors.

Every request to the Kanal API is authenticated with an API key passed in the `Authorization` header. We recommend also adding the `Accept: application/json` header, so that you receive JSON responses, including for errors.

```text
Authorization: Bearer 8fK2pX9mWq4Ld7Vb3Nc6Ts1Z
Accept: application/json
```

The key is a 24-character token. It has no prefix: pass it exactly as it appears in the app.

## Creating an API key

1.  Click your team name, then **Settings**.
    
2.  Open **Developers** > **API Keys**.
    
3.  Click **Add API key**, give it a descriptive name (for example `production-shop`), then confirm with **Create**.
    
4.  Copy the key immediately into your password manager or secret vault.
    

> **Warning:** **The full key is shown only once**, when it is created. After that, it stays visible in masked form, with only its last 4 characters. If you lose it, delete it and create a new one.

You can create several keys, find them in the **My API keys** table, and delete any of them at any time. Deletion is immediate and irreversible.

## What the key is attached to

An API key is attached to **a WhatsApp number**, not to the team. If your team uses several numbers, each number has its own list of keys. The key's team is the one that owns the WhatsApp Business account this number belongs to.

-   **Messaging API**: the key itself determines the sending WhatsApp number. These endpoints do not take a `store_id`.
    
-   **Commerce API**: the key gives access to the stores of that team.
    

## Keeping your keys secure

Keep your keys **server-side only**. Never embed them in a browser, a mobile app, or any environment controlled by the end user. If a key leaks, delete it from **Settings > Developers > API Keys** and generate a new one.

## Your store\_id and store-scoped keys

Commerce API endpoints contain a numeric `store_id` in their path. It identifies the store the data belongs to.

You manage this information yourself in **Settings > Stores**, on a store of the **Custom store** type:

-   the **Guide** tab shows the store's `store_id`: it is the number that follows `/stores/` in the cURL example;
    
-   the **API & ingestion** tab provides an **API ingestion key** limited to that single store, which you can regenerate or revoke. Like an API key, it is shown in full only once: copy it right away.
    

The full walkthrough is in [Connect a non-Shopify store (custom store)](https://help.getkanal.com/en/articles/126-connect-a-non-shopify-store-custom-store.md).

A request is authorized when the key's team owns the store targeted in the URL. An ingestion key only works for its own store's `store_id`. Any other combination returns a 403: a key can never write to a store outside its team.

> **Info:** An ingestion key also works on the Messaging API: it can send messages, not only store data. Protect it like a regular API key.

## Authentication errors

<table style="min-width: 75px;"><colgroup><col style="min-width: 25px;"><col style="min-width: 25px;"><col style="min-width: 25px;"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p><strong>Situation</strong></p></th><th colspan="1" rowspan="1"><p><strong>Code</strong></p></th><th colspan="1" rowspan="1"><p><strong>Response</strong></p></th></tr><tr><td colspan="1" rowspan="1"><p>Authorization header missing</p></td><td colspan="1" rowspan="1"><p><code>401</code></p></td><td colspan="1" rowspan="1"><p><code>API key is missing</code></p></td></tr><tr><td colspan="1" rowspan="1"><p>Unknown or deleted key</p></td><td colspan="1" rowspan="1"><p><code>401</code></p></td><td colspan="1" rowspan="1"><p><code>Invalid API key</code></p></td></tr><tr><td colspan="1" rowspan="1"><p>Valid key but not authorized for this store</p></td><td colspan="1" rowspan="1"><p><code>403</code></p></td><td colspan="1" rowspan="1"><p><code>API key does not authorize this store</code></p></td></tr><tr><td colspan="1" rowspan="1"><p>Unknown store_id, or store paused</p></td><td colspan="1" rowspan="1"><p><code>404</code></p></td><td colspan="1" rowspan="1"><p><code>Store not found or paused</code></p></td></tr><tr><td colspan="1" rowspan="1"><p>Team without an active subscription (Messaging API)</p></td><td colspan="1" rowspan="1"><p><code>403</code></p></td><td colspan="1" rowspan="1"><p><code>Team has no active subscription</code></p></td></tr></tbody></table>

## Verifying your setup

The simplest call to validate the key, the store and the authorization all at once is a customer upsert. A 2xx response confirms everything is correct:

```bash
curl -X POST https://api.getkanal.com/api/v1/stores/123/customers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+33612345678", "first_name": "Test" }'
```

To verify a key meant for the Messaging API, call `POST /api/v1/me` instead: the response returns the WhatsApp number and verified name attached to the key.
