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

# OAuth Connection

> Merchants connect to your app via standard OAuth 2.0. Vambe redirects them to your site, exchanges the code, and stores an access token per installation.

## Why OAuth

A merchant connects their store to your app **only through OAuth 2.0 authorization code**.
They are redirected to *your* site to approve scopes — Vambe never collects their credentials
in a form. The access token you return is the credential Vambe uses for every
[outbound call](/docs/app-platform/outbound-capabilities).

## Fixed redirect URI

Register this exact callback in your OAuth app:

```
https://api.vambe.me/api/public/apps/oauth/callback
```

## The flow

<Steps>
  <Step title="Merchant starts the connection">
    In Vambe the merchant clicks **Connect** on your app. Vambe builds the authorization URL
    from your `oauth.authorize_url` and redirects the merchant's browser to:

    ```
    {authorize_url}
      ?response_type=code
      &client_id={your client_id}
      &redirect_uri=https://api.vambe.me/api/public/apps/oauth/callback
      &scope={space-separated scopes}
      &state={opaque, signed by Vambe}
    ```

    <Warning>
      Treat `state` as opaque and echo it back unchanged. It is encrypted by Vambe and binds
      the callback to the right app and merchant.
    </Warning>
  </Step>

  <Step title="Merchant approves on your site">
    Your authorization page authenticates the merchant and asks them to approve the scopes.
  </Step>

  <Step title="You redirect back with a code">
    Redirect to the fixed `redirect_uri` with the `code` and the original `state`:

    ```
    https://api.vambe.me/api/public/apps/oauth/callback?code={auth_code}&state={state}
    ```
  </Step>

  <Step title="Vambe exchanges the code">
    Vambe POSTs your `oauth.token_url` (`application/x-www-form-urlencoded`):

    ```
    grant_type=authorization_code
    code={auth_code}
    redirect_uri=https://api.vambe.me/api/public/apps/oauth/callback
    client_id={your client_id}
    client_secret={your client_secret}
    ```

    Respond with JSON:

    ```json theme={null}
    {
      "access_token": "the-merchant-access-token",
      "refresh_token": "optional",
      "expires_in": 3600,
      "scope": "read_orders read_products"
    }
    ```

    <Note>
      The `access_token` you return is sent back to you as `Authorization: Bearer …` on every
      outbound call. Make it a token that authorizes API access for that specific store.
    </Note>
  </Step>

  <Step title="(Optional) Vambe fetches the store identity">
    If you set `oauth.account_info_url`, Vambe immediately calls it (`GET`, with
    `Authorization: Bearer {access_token}`) and expects:

    ```json theme={null}
    { "external_id": "store_12345", "name": "Acme Store" }
    ```

    Vambe stores `external_id` on the installation. This is **required for multi-store apps**:
    it lets inbound webhooks resolve which merchant an event belongs to (see
    [Inbound Webhooks → resolving the installation](/docs/app-platform/inbound-webhooks#resolving-the-installation)).
  </Step>
</Steps>

## After connection

Vambe creates an installation (an api token) bound to your app, holding the merchant's
`access_token` (encrypted) and `external_id`. From here:

* You can start pushing [inbound webhooks](/docs/app-platform/inbound-webhooks) for that store.
* Vambe can call your [outbound capabilities](/docs/app-platform/outbound-capabilities) for that store.

<Note>
  Token refresh: store the `refresh_token` and `expires_in` you return; managed refresh on
  Vambe's side is on the roadmap. For now, return long-lived access tokens or tokens you can
  validate server-side on each outbound call.
</Note>
