# API reference

Your app calls the same REST API that merchants use, at `https://api.dzbuild.app/v1`. Two references describe it, and this page covers what changes when you call it with an install token.

## Two references[​](#two-references "Direct link to Two references")

**The API documentation on dzbuild.com** explains the main resources with their parameters, responses and examples, in three languages:

* English: [dzbuild.com/api-docs](https://dzbuild.com/api-docs/intro)
* Arabic: [dzbuild.com/ar/api-docs](https://dzbuild.com/ar/api-docs/intro)
* French: [dzbuild.com/fr/api-docs](https://dzbuild.com/fr/api-docs/intro)

Those pages are written for merchant API keys. With an install token, the rules on this page win where they differ: any plan can use your app, the limits are in [Rate limits](https://dzbuild.dev/rate-limits.md), and some endpoints are closed to apps.

**The OpenAPI description for apps** is one JSON file in OpenAPI 3.1 format. It lists the 92 operations an install token can call, with their scopes, parameters and response shapes. Import it into Postman or Insomnia, or generate types from it.

[Download dzbuild-apps-v1.json](https://dzbuild.dev/openapi/dzbuild-apps-v1.json)

```
curl -sO https://dzbuild.dev/openapi/dzbuild-apps-v1.json
```

The file declares `https://api.dzbuild.app` as its server. Its `dzOAuth` security scheme lists every scope with an English description.

## Sending the install token[​](#sending-the-install-token "Direct link to Sending the install token")

The token exchange gives you one access token per store the merchant approved (see [OAuth](https://dzbuild.dev/oauth.md)). Each token starts with `dzpk_live_`. Send it in the `Authorization` header with the `Bearer` scheme:

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

  -H "Authorization: Bearer dzpk_live_xxxxxxxx"
```

The token decides the store. There is no store parameter on the requests, so to work on another store of the same merchant, use that store's token from the `stores` list of the token response. Keep tokens on your server. They do not expire on their own. A token stops working when the merchant uninstalls your app, or when the merchant installs it again on the same store, which replaces the token.

| Status | Message                            | Cause                                                  |
| ------ | ---------------------------------- | ------------------------------------------------------ |
| `401`  | `Missing Authorization header`     | No `Authorization` header.                             |
| `401`  | `Unsupported Authorization scheme` | The header does not start with `Bearer`.               |
| `401`  | `Invalid or revoked API key`       | The token is wrong, or it was revoked by an uninstall. |

Every install token is also checked against the state of your app and of the store. A refused call answers `403` with one of these codes:

| Code                | Meaning                                                          |
| ------------------- | ---------------------------------------------------------------- |
| `app_uninstalled`   | The app is no longer installed on this store.                    |
| `app_suspended`     | DZBuild suspended the app.                                       |
| `app_not_approved`  | The app is in test mode and only runs on its developer's stores. |
| `app_plan_required` | The store's plan is below the minimum plan you set for the app.  |

## Responses[​](#responses "Direct link to Responses")

A successful response puts the result in `data`. An error puts a `code` and a `message` in `error`. Both carry `meta.request_id`; quote it when you contact DZBuild about a call.

```
{

  "error": { "code": "forbidden", "message": "Missing scope: orders:write" },

  "meta": { "request_id": "8f2c1a9d4b7e6035", "api_version": "v1" }

}
```

List endpoints answer:

```
{

  "data": { "items": [...], "next_cursor": "...", "has_more": true },

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

}
```

Send `next_cursor` back as `cursor` to get the next page, and stop when `has_more` is `false`. `GET /v1/orders` also accepts `since` (orders created at or after that time), `status` and `customer_phone`.

## whoami[​](#whoami "Direct link to whoami")

`GET /v1/whoami` needs no scope. It tells you which store a token belongs to and what it may do. For an install token it adds an `app` object:

```
{

  "data": {

    "key_id": "dzpk_live_3c9e1a7f5b2d80",

    "store_id": 1234,

    "type": "platform",

    "rate_limit_tier": "enterprise",

    "pilot": true,

    "scopes": ["orders:read", "whatsapp:read", "whatsapp:send"],

    "app": {

      "app_id": 12,

      "client_id": "dzapp_4e1b9c07d2a86f35e0b1",

      "install_id": 57

    }

  },

  "meta": { "request_id": "8f2c1a9d4b7e6035", "api_version": "v1" }

}
```

| Field             | Meaning                                                                                |
| ----------------- | -------------------------------------------------------------------------------------- |
| `store_id`        | The store this token works on.                                                         |
| `scopes`          | The scopes the merchant granted.                                                       |
| `rate_limit_tier` | Always `enterprise` for install tokens, whatever the store's plan.                     |
| `app.app_id`      | Your app's id.                                                                         |
| `app.client_id`   | Your app's OAuth client id.                                                            |
| `app.install_id`  | The install on this store. Webhook payloads such as `app.uninstalled` use the same id. |

## Endpoints closed to apps[​](#endpoints-closed-to-apps "Direct link to Endpoints closed to apps")

These endpoints answer `403` to an install token, whatever its scopes:

| Endpoints                                            | Answer                          | Why                                                                                                                        |
| ---------------------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `/v1/keys` and `/v1/keys/{key_id}`                   | `Apps cannot use this endpoint` | API keys belong to the merchant.                                                                                           |
| `/v1/webhooks` and everything under it               | `Apps cannot use this endpoint` | Your app's webhook is set once in the developer console for every store (see [Webhooks](https://dzbuild.dev/webhooks.md)). |
| `/v1/changes` and everything under it, undo included | `Apps cannot use this endpoint` | The change log and undo stay with the merchant.                                                                            |

`POST /v1/landing-pages/generate` needs the `ai:generate` scope, which apps cannot request because it spends the merchant's AI credits. It answers `403` with `Missing scope: ai:generate`.
