# Authentification

Deux types de clés.

## Clé de plateforme (serveur à serveur, CRUD complet)[​](#clé-de-plateforme-serveur-à-serveur-crud-complet "Lien direct vers Clé de plateforme (serveur à serveur, CRUD complet)")

Utilisez un Bearer token depuis votre back-end :

```
Authorization: Bearer <key_id>.<key_secret>
```

Le format est `key_id.key_secret`, les deux moitiés sont requises. `key_id` est l'identifiant de 24 caractères qui commence déjà par `dzpk_live_` (par exemple `dzpk_live_xxxxxxxxxxxxxx.<48-hex secret>`) : ne rajoutez donc pas le préfixe. Le secret de la clé fait 48 caractères hexadécimaux et n'est affiché qu'**une seule fois** à la création, jamais ensuite.

## Clé publique (sites et applications externes ; signée HMAC)[​](#clé-publique-sites-et-applications-externes--signée-hmac "Lien direct vers Clé publique (sites et applications externes ; signée HMAC)")

Pour comptabiliser les **inscriptions** d'utilisateurs finaux et les **événements** personnalisés depuis un site ou une application que vous exploitez en dehors de DZBuild. Votre back-end appelle `POST /v1/signups` / `POST /v1/events` et signe chaque requête — n'exposez jamais le secret de signature au navigateur.

En-têtes :

```
Authorization: DZ-Public <key_id>

X-DZ-Timestamp: <unix_seconds>

X-DZ-Nonce: <32-hex>

X-DZ-Signature: hex(hmac_sha256(signing_secret, key_id + "\n" + nonce + "\n" + ts + "\n" + sha256(body)))
```

Ici aussi, `key_id` commence déjà par `dzpub_live_` — transmettez-le exactement tel qu'il vous a été retourné. Le secret de signature fait 64 caractères hexadécimaux.

Le nonce est à usage unique par clé pendant une heure et empêche le rejeu. Le timestamp doit être dans les ±5 minutes.

Une nouvelle clé publique reste inerte tant qu'elle n'est pas activée

Une clé `type: public` créée via `POST /v1/keys` renvoie `401` tant qu'elle n'a pas été activée pour le trafic API. Contactez le support juste après en avoir créé une pour la faire activer. Les clés de plateforme (Bearer) ne sont pas concernées — elles fonctionnent immédiatement.

## Scopes[​](#scopes "Lien direct vers Scopes")

Chaque clé possède une liste de scopes. Scopes de plateforme par défaut : `store:read`, `store:write`, `products:read`, `products:write`, `orders:read`, `orders:write`, `customers:read`, `landing_pages:read`, `landing_pages:write`, `promos:read`, `promos:write`, `pixels:read`, `pixels:write`, `shipping:read`, `shipping:write`, `webhooks:read`, `webhooks:write`, `usage:read`, `analytics:read`, `whatsapp:read`, `whatsapp:send`. Une clé créée depuis le tableau de bord reçoit exactement cette liste. `delivery:send` et `ai:generate` n'en font pas partie : une clé créée depuis le tableau de bord ou via `POST /v1/keys` reçoit donc `403` sur `POST /v1/orders/{id}/send-to-delivery` et `POST /v1/landing-pages/generate`.

Scopes publics par défaut : `signups:write`, `events:write`.

Les scopes sont vérifiés en lecture comme en écriture : une clé sans `orders:read` reçoit `403` avec `Missing scope: orders:read` sur `GET /v1/orders`. `store:write` couvre les écritures des réglages de la boutique, du design, du thème et des sections de la page d'accueil. `signups:write` et `events:write` couvrent `POST /v1/signups` et `POST /v1/events`.

La gestion des clés (`/v1/keys`) est contrôlée par le **type** de clé, pas par les scopes : une clé publique qui l'appelle reçoit `403` — « Key management requires a platform key ».

Une clé de plateforme créée via `POST /v1/keys` ne reçoit que les scopes que la clé appelante possède déjà (`403` si elles n'en partagent aucun). Une clé `type: public` reçoit toujours `signups:write` et `events:write`.

## Créer une clé[​](#créer-une-clé "Lien direct vers Créer une clé")

Le propriétaire d'une boutique avec un plan Enterprise actif crée ses clés personnelles depuis le tableau de bord, dans **Paramètres → API** (`/dashboard/api`). Une nouvelle clé est inscrite au pilote automatiquement et fonctionne tout de suite : il n'y a rien à demander au support. La page affiche deux valeurs, une seule fois, à la création de la clé :

* **Clé d'accès (Bearer token)** : c'est la clé entière, déjà sous la forme `key_id.key_secret`. Envoyez-la telle quelle, `Authorization: Bearer <bearer token>`, sans rien y ajouter.
* **Secret de signature (Signing secret)** : il ne va jamais dans l'en-tête `Authorization`, et les appels Bearer ne l'utilisent pas. Gardez-le privé, comme la clé d'accès.

Une boutique détient au plus 3 clés personnelles actives. Les clés des applications installées, de Copilot ou d'un connecteur n'occupent aucune de ces places.

## Connexions des assistants[​](#connexions-des-assistants "Lien direct vers Connexions des assistants")

Une connexion créée pour Copilot ou pour un assistant IA connecté (Claude ou ChatGPT) peut couvrir plusieurs boutiques du marchand, avec une clé par boutique. Deux endpoints permettent à une clé détenue par une telle connexion de lire les boutiques qu'elle couvre et de changer celle qui est active. Toute autre clé, y compris une clé créée depuis le tableau de bord, reçoit `404 not_found` avec `This key does not belong to an assistant connection.`

### `GET /v1/connection`[​](#get-v1connection "Lien direct vers get-v1connection")

Demande `store:read`.

```
curl https://api.dzbuild.app/v1/connection \

  -H "Authorization: Bearer $DZ_KEY"
```

```
{ "data": { "connection_id": 100, "client_name": "Claude", "active_store_id": 10,

            "stores": [ { "id": 10, "name": "My store", "slug": "my-store" },

                        { "id": 20, "name": "My second store", "slug": "my-second-store" } ] },

  "meta": { "request_id": "...", "api_version": "v1" } }
```

`client_name` est le nom de l'application de l'assistant. Une connexion approuvée avant que les connexions puissent couvrir plusieurs boutiques liste son unique boutique.

### `POST /v1/connection/active-store`[​](#post-v1connectionactive-store "Lien direct vers post-v1connectionactive-store")

Demande `store:write` et une `Idempotency-Key`. `store_id` dans le corps désigne la boutique à rendre active.

```
curl -X POST https://api.dzbuild.app/v1/connection/active-store \

  -H "Authorization: Bearer $DZ_KEY" \

  -H "Content-Type: application/json" \

  -H "Idempotency-Key: active-store-20" \

  -d '{"store_id": 20}'
```

La réponse est la connexion après le changement, sous la même forme que `GET /v1/connection`. La boutique active est un pointeur, pas une permission : chaque requête agit toujours sur la seule boutique à laquelle appartient sa clé. Une boutique hors de la connexion répond `403 store_not_in_connection`, et un corps sans `store_id` répond `400 bad_request`.
