
# Partner Connect

Connecting external services to Bitrix24: your application asks the user for permission to access their Bitrix24 account and receives a Vibecode API key for subsequent calls. The flow is built on the Authorization Code scheme — the same one used by OAuth providers like Google or GitHub.

**Base URL:** `https://vibecode.bitrix24.com/v1` | **Authorization:** the partner's `client_id` + `client_secret` | **Key scopes:** requested on the consent page

## Contents

- [When to use](#when-to-use)
- [How it works](#how-it-works)
- [Endpoint reference](#endpoint-reference)
- [Full scenario](#full-scenario) — an Express handler end to end
- [`GET /v1/connect/authorize`](#get-v1-connect-authorize) — flow start, redirect to consent
- [`POST /v1/connect/token`](#post-v1-connect-token) — exchanging the code for an API key
- [Using the API key](#using-the-api-key)
- [Available scopes](#available-scopes)
- [Key lifetime and revocation](#key-lifetime-and-revocation)
- [Security](#security)
- [Partner registration](#partner-registration)
- [See also](#see-also)

## When to use

The scenario is an external SaaS product that integrates with your clients' Bitrix24 accounts: CRM analytics, ERP synchronization, a chat assistant, a landing page builder. A "Connect Bitrix24" button on your site launches the flow: the user selects a Bitrix24 account and confirms the scopes, your server receives a permanent API key and works with the Bitrix24 account on behalf of the user.

If you are building an application that is installed **inside** a Bitrix24 account and works only with it, use a regular API key, see [Authorization and keys](/docs/keys-auth).

## How it works

```
Your application → [1. Redirect] → Vibecode Consent Page → [2. Consent]
    ↑                                                          ↓
    └──── [4. API key] ←── [3. Code → redirect_uri] ──────────┘
```

1. **Redirect** — you send the user to `/v1/connect/authorize` with `client_id`, `redirect_uri`, `state`, and a list of scopes.
2. **Consent** — the user sees a Vibecode page, selects a Bitrix24 account, and confirms or declines the requested scopes.
3. **Code** — after approval the user returns to `redirect_uri` with the `code` and `state` parameters. On decline — `redirect_uri?error=access_denied&state=...`.
4. **Exchange** — the partner's server sends `POST /v1/connect/token` and receives an API key.

## Endpoint reference

| Method | Path | Description |
|-------|------|----------|
| GET | [`/v1/connect/authorize`](#get-v1-connect-authorize) | Flow start: redirect to the consent page |
| POST | [`/v1/connect/token`](#post-v1-connect-token) | Exchange a one-time code for a permanent API key |

## Full scenario

An example Express handler that walks the user through both endpoints end to end. Before launching, place the `client_id` and `client_secret`, issued by the Alaio Vibecode team, into environment variables, and register the `redirect_uri` with the partner.

```javascript
import express from 'express'
import crypto from 'node:crypto'

const app = express()
const sessions = new Map() // in production — Redis or a DB

const CLIENT_ID = process.env.PARTNER_CLIENT_ID
const CLIENT_SECRET = process.env.PARTNER_CLIENT_SECRET
const REDIRECT_URI = 'https://yourapp.com/callback'

// 1. The "Connect Bitrix24" button leads here
app.get('/connect', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex')
  sessions.set(state, { userId: req.user.id, createdAt: Date.now() })

  const params = new URLSearchParams({
    client_id: CLIENT_ID,
    redirect_uri: REDIRECT_URI,
    scopes: 'crm,task',
    state,
  })
  res.redirect(`https://vibecode.bitrix24.com/v1/connect/authorize?${params}`)
})

// 2. Vibecode returns the user here after consent or decline
app.get('/callback', async (req, res) => {
  const { code, state, error } = req.query

  const session = sessions.get(state)
  if (!session) return res.status(400).send('Unknown state')
  sessions.delete(state)

  if (error === 'access_denied') {
    return res.redirect('/dashboard?connect=denied')
  }

  // 3. Exchange the code for an API key — a server-side request with client_secret
  const tokenRes = await fetch('https://vibecode.bitrix24.com/v1/connect/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      code,
      redirect_uri: REDIRECT_URI,
    }),
  })
  const data = await tokenRes.json()

  if (!data.success) {
    return res.status(400).send(`Exchange error: ${data.error.code}`)
  }

  // 4. Store the binding: our service user ↔ Bitrix24 portal
  await db.connections.upsert({
    userId: session.userId,
    portalDomain: data.portal.domain,
    portalName: data.portal.name,
    apiKey: encrypt(data.api_key), // secret, encrypt before storing
    scopes: data.scopes,
  })

  res.redirect('/dashboard?connect=ok')
})

// 5. From here on we use the stored key for calls on behalf of the user
async function listDeals(userId) {
  const connection = await db.connections.findByUserId(userId)
  const apiKey = decrypt(connection.apiKey)

  const res = await fetch('https://vibecode.bitrix24.com/v1/deals?limit=10', {
    headers: { 'X-Api-Key': apiKey },
  })
  return res.json()
}
```

Key points of the scenario:

- `state` is generated on the server and verified on return — without this check an attacker could slip the user someone else's code.
- `client_secret` is kept only on the server and never reaches the browser.
- The API key is encrypted before being written to the DB and decrypted only at the moment of a call.
- On `error=access_denied` the user sees a clear message rather than an exchange error page.

## GET /v1/connect/authorize

Redirects the user to the Alaio Vibecode consent page.

**Query parameters:**

| Parameter | Type | Req. | Description |
|----------|-----|:-----:|----------|
| `client_id` | string | yes | Partner identifier, issued by the Alaio Vibecode team |
| `redirect_uri` | string | yes | Callback URL. Must match one of those registered with the partner |
| `state` | string | yes | An arbitrary string that will be returned along with the code. CSRF protection |
| `scopes` | string | no | Comma-separated list of scopes: `crm,task,im`. If not passed — the default scopes from the partner settings apply |

**Example URL:**

```
https://vibecode.bitrix24.com/v1/connect/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=https://yourapp.com/callback&scopes=crm,task&state=abc123random
```

**Successful redirect** after approval:

```
https://yourapp.com/callback?code=AUTH_CODE_HERE&state=abc123random
```

**Redirect on decline** by the user on the consent page:

```
https://yourapp.com/callback?error=access_denied&state=abc123random
```

### Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_REQUEST` | One of `client_id`, `redirect_uri`, `state` was not passed |
| 400 | `INVALID_CLIENT` | `client_id` is not registered or the partner is disabled |
| 400 | `INVALID_REDIRECT_URI` | `redirect_uri` does not match any of those registered with the partner |
| 400 | `INVALID_SCOPE` | One or more scopes are not in the list allowed for Bitrix24 |

The full reference of general API errors — [Errors](/docs/errors).

## POST /v1/connect/token

Exchanges a one-time authorization code for a permanent API key. Accepts `application/json` and `application/x-www-form-urlencoded`.

**Request fields (body):**

| Field | Type | Req. | Description |
|------|-----|:-----:|----------|
| `client_id` | string | yes | Partner identifier |
| `client_secret` | string | yes | Partner secret. Pass only from the server side |
| `code` | string | yes | The code from the `code` parameter of the redirect |
| `redirect_uri` | string | yes | The same `redirect_uri` that was passed to `/v1/connect/authorize` |

### Examples

#### curl

```bash
curl -X POST https://vibecode.bitrix24.com/v1/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d code=RECEIVED_CODE \
  -d redirect_uri=https://yourapp.com/callback
```

#### JavaScript

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
    code: receivedCode,
    redirect_uri: 'https://yourapp.com/callback',
  }),
})

const data = await res.json()
// data.api_key — permanent Vibecode API key
// data.portal — the portal selected by the user
// data.scopes — the confirmed scopes
// data.user — the user who granted access
```

### Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on a successful exchange |
| `api_key` | string | Vibecode API key in the `vibe_app_...` format. Pass it in the `X-Api-Key` header on subsequent calls |
| `portal.domain` | string | Bitrix24 account domain, for example `example.bitrix24.com` |
| `portal.name` | string | Bitrix24 account name |
| `scopes` | string[] | List of scopes the user confirmed. May be shorter than requested if the user removed some |
| `user.name` | string | Name of the user who granted access |
| `user.email` | string | The user's email |

### Response example

```json
{
  "success": true,
  "api_key": "vibe_app_...",
  "portal": {
    "domain": "example.bitrix24.com",
    "name": "My company"
  },
  "scopes": ["crm", "task"],
  "user": {
    "name": "John Smith",
    "email": "john@example.com"
  }
}
```

### Error response example

400 — a required parameter is missing:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Missing required parameters"
  }
}
```

### Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_REQUEST` | One of `client_id`, `client_secret`, `code`, `redirect_uri` was not passed |
| 400 | `INVALID_CODE` | The code does not exist, has expired (5 minutes), has already been used, or `redirect_uri` differs from the one passed to `/v1/connect/authorize` |
| 401 | `INVALID_CLIENT` | `client_id` is unknown or `client_secret` does not match |
| 403 | `PARTNER_DISABLED` | The partner account is suspended |

The full reference of general API errors — [Errors](/docs/errors).

## Using the API key

The received key is of type `APP` and works like a standard Vibecode API key. Pass it in the `X-Api-Key` header:

```bash
curl -H "X-Api-Key: vibe_app_..." \
  https://vibecode.bitrix24.com/v1/deals
```

The same key can be used with any Vibecode API endpoint within the confirmed scopes: deal lists, batch requests, aggregation, and so on.

Unlike a key created in the cabinet, a partner key is **not** automatically granted the platform scopes `vibe:ai` (AI router) and `vibe:search` (web search) — it carries exactly the permissions the user confirmed on the consent screen. Calls to the AI router (`/v1/chat/completions`) and web search (`/v1/search`) through a partner key therefore return `403` by default.

The partner key works with a single `X-Api-Key` header and does **not** require `Authorization: Bearer <session_token>`. This distinguishes it from OAuth application keys from the Vibecode catalog with the same `vibe_app_...` prefix — there a user session is mandatory.

## Available scopes

When calling `/v1/connect/authorize`, pass the same scopes you would when creating a standard API key in a Bitrix24 account. On the consent page the user sees the list and can remove individual items — the final set arrives in the `scopes` field of the `/v1/connect/token` response.

The full list of supported values (32 scopes: `crm`, `task`, `tasks`, `im`, `imbot`, `imopenlines`, `call`, `telephony`, `bizproc`, `calendar`, `timeman`, `catalog`, `sale`, `lists`, `disk`, `entity`, `user`, `user_basic`, `user_brief`, `user.userfield`, `department`, `landing`, `documentgenerator`, `sign.b2e`, `sonet_group`, `log`, `vote`, `ai_admin`, `biconnector`, `booking`, `delivery`, `pay_system`, `main`, `placement`, `userfieldtype`) is described in the [Authorization and keys](/docs/keys-auth) section.

## Key lifetime and revocation

- **The authorization code (`code`)** is valid for **5 minutes** and is one-time. After the exchange via `/v1/connect/token`, a repeat call with the same code will return `INVALID_CODE`.
- **The consent state** (the internal state of the consent page) lives 10 minutes — if the user does not confirm within that time, the link has to be issued again.
- **The API key** has no expiration. It works until:
  - the user revokes access in the Bitrix24 account (on the granted-permissions management page in their account),
  - or the Alaio Vibecode team suspends the partner application.

When a key is revoked, all requests with it return `401 KEY_INACTIVE`. If the key is deleted or unknown — `401 INVALID_API_KEY`. The partner must handle both codes correctly and prompt the user to re-authorize.

## Security

- **State parameter** — generate a cryptographically strong random string for each request and verify it on return to `redirect_uri`. Protects against CSRF.
- **`client_secret` — server only.** Never pass the secret to a browser, mobile app, or client-side code. The code-for-key exchange is performed only by a server-side request.
- **Key storage.** The API key is a secret that grants access to the user's data. Store it encrypted, restrict access to the connection string, do not log it.
- **`redirect_uri` binding.** The value in `/v1/connect/authorize` and `/v1/connect/token` must match character for character — a mismatch will lead to `INVALID_CODE`.

## Partner registration

Self-service registration is not yet available — `client_id` and `client_secret` are issued by the Alaio Vibecode team after reviewing the application. To submit a request, write to `partners@bitrix24.com`.

In the request specify:

- the name and a short description of the application,
- the use case,
- the list of requested scopes,
- one or more `redirect_uri` values you will use.

## See also

- [Authorization and keys](/docs/keys-auth) — general rules for working with Vibecode API keys, key types (including OAuth applications), the list of scopes
- [Management keys](/docs/management-keys) — programmatic key creation for your own Bitrix24 account
- [API errors](/docs/errors) — the general error-code reference
