# API Quickstart

> Configure credentials, environment variables, and make your first sandbox API call.

Source: https://help.boltapp.com/api-reference/api-quickstart

Use the Bolt API to create orders, authorize payments, manage shopper accounts, and receive webhooks. Your server makes **outbound** REST calls to Bolt; Bolt makes **inbound** callbacks to your server for cart, shipping, and tax.

## Prerequisites [#prerequisites]

* A [Bolt merchant account](https://merchant.boltapp.com/onboarding/get-started)
* Access to the [sandbox Merchant Dashboard](https://merchant-sandbox.boltapp.com)

## Get credentials [#get-credentials]

Copy these values from **Administration → API** in your dashboard:

| Key                 | Use                                                                             |
| ------------------- | ------------------------------------------------------------------------------- |
| **API key**         | Server-side outbound API calls (`X-API-Key` header)                             |
| **Signing secret**  | Verify inbound webhooks and Merchant Callback requests                          |
| **Publishable key** | Client-side SDK initialization (checkout modal, Connect, embeddable components) |

Sandbox and production each have separate keys. See [API keys](/getting-started/api-keys) for dashboard screenshots and key rotation.

## Configure your environment [#configure-your-environment]

Store credentials in environment variables. Never commit keys to source control. For production, set `BOLT_ENV=production` and `BOLT_API_BASE_URL=https://api.boltapp.com` with production keys.

<CodeGroup>
  <CodeBlockTabs defaultValue=".env">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value=".env">
        .env
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="JavaScript">
        JavaScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value=".env">
      ```bash
      BOLT_ENV=sandbox
      BOLT_API_BASE_URL=https://api-sandbox.boltapp.com
      BOLT_API_KEY=your_sandbox_api_key
      BOLT_SIGNING_SECRET=your_sandbox_signing_secret
      BOLT_PUBLISHABLE_KEY=your_sandbox_publishable_key
      ```
    </CodeBlockTab>

    <CodeBlockTab value="TypeScript">
      ```typescript
      type BoltEnv = "sandbox" | "production";

      const env: BoltEnv = (process.env.BOLT_ENV as BoltEnv) ?? "sandbox";
      const baseUrl: string =
        process.env.BOLT_API_BASE_URL ??
        (env === "production"
          ? "https://api.boltapp.com"
          : "https://api-sandbox.boltapp.com");

      function required(name: string): string {
        const value = process.env[name];
        if (!value) throw new Error(`Missing environment variable ${name}`);
        return value;
      }

      const apiKey = required("BOLT_API_KEY");
      const signingSecret = required("BOLT_SIGNING_SECRET");
      const publishableKey = required("BOLT_PUBLISHABLE_KEY");
      ```
    </CodeBlockTab>

    <CodeBlockTab value="JavaScript">
      ```javascript
      const env = process.env.BOLT_ENV ?? "sandbox";
      const baseUrl =
        process.env.BOLT_API_BASE_URL ??
        (env === "production"
          ? "https://api.boltapp.com"
          : "https://api-sandbox.boltapp.com");

      const apiKey = process.env.BOLT_API_KEY;
      const signingSecret = process.env.BOLT_SIGNING_SECRET;
      const publishableKey = process.env.BOLT_PUBLISHABLE_KEY;
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python
      import os

      env = os.environ.get("BOLT_ENV", "sandbox")
      base_url = os.environ.get(
          "BOLT_API_BASE_URL",
          "https://api.boltapp.com" if env == "production" else "https://api-sandbox.boltapp.com",
      )
      api_key = os.environ["BOLT_API_KEY"]
      signing_secret = os.environ["BOLT_SIGNING_SECRET"]
      publishable_key = os.environ["BOLT_PUBLISHABLE_KEY"]
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

<Warning>
  Never use sandbox keys against `api.boltapp.com` or production keys against `api-sandbox.boltapp.com`. A key from the other environment is rejected as invalid: `403` with error code `1005`.
</Warning>

See [Environments](/api-reference/environments) for CDN URLs, divisions, and approved domains.

## Make your first request [#make-your-first-request]

List recent transactions in sandbox to confirm your API key and base URL are correct.

<CodeGroup>
  <CodeBlockTabs defaultValue="TypeScript">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="JavaScript">
        JavaScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="cURL">
        cURL
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="TypeScript">
      ```typescript
      interface TransactionsResponse {
        transactions: Array<{ reference: string; status: string }>;
      }

      const response = await fetch(`${baseUrl}/v1/merchant/transactions`, {
        headers: {
          "X-API-Key": apiKey,
          "Content-Type": "application/json",
        },
      });

      if (!response.ok) throw new Error(`Request failed: ${response.status}`);

      const data = (await response.json()) as TransactionsResponse;
      ```
    </CodeBlockTab>

    <CodeBlockTab value="JavaScript">
      ```javascript
      const response = await fetch(`${baseUrl}/v1/merchant/transactions`, {
        headers: {
          "X-API-Key": apiKey,
          "Content-Type": "application/json",
        },
      });
      const data = await response.json();
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```python
      import requests

      response = requests.get(
          f"{base_url}/v1/merchant/transactions",
          headers={"X-API-Key": api_key, "Content-Type": "application/json"},
      )
      data = response.json()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash
      curl "https://api-sandbox.boltapp.com/v1/merchant/transactions" \
        -H "X-API-Key: YOUR_API_KEY" \
        -H "Content-Type: application/json"
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

**Expected result:** HTTP `200` with a JSON response.

If you receive `403` with error code `1005`, a key reached Bolt and was rejected: confirm you are using the **API key** (not the publishable key) and the matching sandbox base URL. That code does not distinguish an invalid key from one whose merchant is no longer active.

If you receive `401` with error code `1015`, no `X-API-Key` header reached Bolt, and this endpoint fell back to checking for a session instead. Check that your client is sending the header. Not every endpoint behaves this way: `POST /v1/merchant/orders` answers a missing key with `403` and `1005`, the same as an invalid one.

See [Authentication](/api-reference/authentication) for inbound HMAC verification, OAuth, and required headers.

## How the docs are organized [#how-the-docs-are-organized]

| Section                                                         | What it covers                                                    |
| --------------------------------------------------------------- | ----------------------------------------------------------------- |
| [Integration guides](/api-reference/guides/embeddable-checkout) | Use-case entry points: checkout, Connect, subscriptions, gaming   |
| [Merchant Callback](/api-reference/merchant-callback/overview)  | Endpoints **Bolt calls on your server** (cart, shipping, tax)     |
| [Endpoints](/api-reference/endpoints/orders/createordertoken)   | Outbound REST resources: orders, transactions, accounts, webhooks |

## Response codes [#response-codes]

| Status | Meaning                                                                                                                                                                                               |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200`  | Success                                                                                                                                                                                               |
| `400`  | Invalid parameters. `/v1/` endpoints return `422` for these instead                                                                                                                                   |
| `401`  | Authentication failed. Returned by `/v3/` endpoints, by `/v1/subscriptions/` endpoints as error code `63`, and by some `/v1/merchant/` endpoints as error code `1015`                                 |
| `403`  | `X-API-Key` was rejected on a `/v1/merchant/` endpoint (error code `1005`). On any version, an OAuth token without the required scope, or a resource you do not have permission for (error code `18`) |
| `404`  | Resource not found                                                                                                                                                                                    |
| `422`  | Validation error on a `/v1/` endpoint; `/v3/` returns `400`                                                                                                                                           |
| `429`  | Rate limited                                                                                                                                                                                          |
| `5xx`  | Bolt server error                                                                                                                                                                                     |

<Note>
  A rejected API key does not return the same status everywhere. `/v1/merchant/` endpoints return `403` with error code `1005`, `/v1/subscriptions/` endpoints return `401` with error code `63`, and `/v3/` endpoints return `401`. Read the error code rather than the status when you need to tell failures apart, because `403` covers two different things: a request that never authenticated, and one that authenticated and was refused on permissions. `1005` is the API key, `1012` is the publishable key, `1015` is a failed session check, `63` is an unspecified authentication failure, and `18` is a permission or scope problem. `/v3/` responses carry no numeric code; read their `.tag` field instead.
</Note>

See [Errors](/api-reference/errors) for Bolt-specific error codes.

## Related [#related]

* [Authentication](/api-reference/authentication)
* [Environments](/api-reference/environments)
* [Test cards](/getting-started/test-cards)
* [Postman collection](https://help.boltapp.com/developers/tools/postman-collection/)
* [Webhooks guide](/api-reference/guides/webhooks)
