> ## Documentation Index
> Fetch the complete documentation index at: https://docs.komerza.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exchange Code

> Exchanges an authorization code for an API key.

## Overview

Exchange an authorization code for a JWT API key. This is the final step in the OAuth2 flow, converting the temporary code into a permanent access token.

<Info>
  This endpoint requires the `X-OAuth2-Client-Secret` header for authentication instead
  of the standard `Authorization` header.
</Info>

## Path Parameters

| Parameter | Type   | Description                                       |
| --------- | ------ | ------------------------------------------------- |
| `appId`   | string | Your application's Client ID                      |
| `code`    | string | The authorization code received from the callback |

## Headers

| Header                   | Required | Description                                   |
| ------------------------ | -------- | --------------------------------------------- |
| `X-OAuth2-Client-Secret` | Yes      | Your application's 72-character client secret |
| `User-Agent`             | Yes      | Your application identifier                   |

<Warning>
  **Server-Side Only**: This request must be made from your backend server,
  never from client-side code. The client secret must remain confidential.
</Warning>

## Response

```json theme={null}
{
  "success": true,
  "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

The `data` field contains a JWT API key that you can use to make authenticated API requests.

## Using the API Key

Include the JWT as a Bearer token in subsequent API requests:

```bash theme={null}
curl -X GET https://api.komerza.com/stores/STORE_ID \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "User-Agent: MyApp/1.0"
```

## Token Properties

The JWT API key:

* **Grants access** only to the stores the user authorized
* **Has permissions** limited to the scopes you requested and the user approved
* **Does not expire** until the user revokes authorization
* **Is tied** to the specific user and application

## Error Responses

| Error                   | Description                                                       |
| ----------------------- | ----------------------------------------------------------------- |
| `invalid_code`          | The authorization code is invalid or has already been used        |
| `code_expired`          | The authorization code has expired (codes are valid for 1 minute) |
| `invalid_client_secret` | The client secret is incorrect                                    |
| `app_not_found`         | The application ID is invalid                                     |

## Complete Flow Example

```javascript theme={null}
// 1. User clicks "Connect with Komerza" in your app
const authUrl = `https://dashboard.komerza.com/auth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&state=${randomState}`;
window.location.href = authUrl;

// 2. User authorizes on Komerza, redirected back to your app
// URL: https://myapp.com/callback?code=ENCRYPTED_CODE&state=randomState

// 3. Your backend exchanges the code for an API key
const response = await fetch(
  `https://api.komerza.com/oauth2/${CLIENT_ID}/exchange/${code}`,
  {
    headers: {
      "X-OAuth2-Client-Secret": process.env.CLIENT_SECRET,
      "User-Agent": "MyApp/1.0",
    },
  }
);

const { data: apiKey } = await response.json();

// 4. Store the API key securely and use it for API calls
const stores = await fetch("https://api.komerza.com/stores", {
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "User-Agent": "MyApp/1.0",
  },
});
```


## API Specification

The full API specification for this endpoint is available in the [documentation index](https://docs.komerza.com/llms.txt).
