For AI agents: markdown of this page — /docs-content-en/cli.md documentation index — /llms.txt

CLI and cURL

A page for those who work with the Vibecode API from the terminal: shell scripts, one-off checks with the curl utility, server-side PHP integrations without an SDK. Full operation references are on the dedicated pages: Entity API, Filtering, Batch API, Error codes.

Base URL — https://vibecode.bitrix24.com. Authorization — via the X-Api-Key header. Responses — JSON in the { success, data, meta } format on success and { success: false, error } on error.

On this page

Environment

Save the key and base URL into environment variables — this removes repetition in every command and keeps the key out of your shell command history.

Terminal
export VIBE_API_KEY="vibe_api_xxx..."
export VIBE_URL="https://vibecode.bitrix24.com"

Check — JSON with the Bitrix24 account and scopes should be returned:

Terminal
curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me" | head -c 200

To persist the variables across sessions, add the export ... lines to ~/.zshrc (for the zsh shell) or ~/.bashrc (for bash) and restart the terminal.

For an authorization key (vibe_app_...) you additionally need a session token:

Terminal
export VIBE_APP_KEY="vibe_app_xxx..."
export VIBE_SESSION_TOKEN="vibe_session_xxx..."

Authorization in curl

Personal key — one header:

Terminal
curl -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals"

Authorization key — two headers, X-Api-Key for the application and Authorization: Bearer for a specific user's session:

Terminal
curl -H "X-Api-Key: $VIBE_APP_KEY" \
     -H "Authorization: Bearer $VIBE_SESSION_TOKEN" \
     "$VIBE_URL/v1/deals"

More on key types and obtaining a session token — Keys and authorization.

Minimal verification cycle

A single scenario to confirm the key works and the API responds: create a deal → delete it. The same set of operations exists for all 40+ entities — only the fields differ (see Entity API and the entity reference).

Terminal
# 1. Create a deal — returns an object with the assigned id
curl -X POST "$VIBE_URL/v1/deals" \
  -H "X-Api-Key: $VIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "CLI test", "stageId": "NEW", "categoryId": 0 }'

# 2. Delete the created deal — success = HTTP 204 with an empty body
curl -i -X DELETE "$VIBE_URL/v1/deals/<id-from-first-response>" \
  -H "X-Api-Key: $VIBE_API_KEY"

The success indicator for DELETE is the response code, not the response body. To see only the code:

Terminal
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE \
  -H "X-Api-Key: $VIBE_API_KEY" \
  "$VIBE_URL/v1/deals/<id>"

Full request examples with filters, sorting, field selection, and auto-pagination are on the page for the relevant entity, for example Deals. Filter syntax (MongoDB-style, prefixes, operators as keys) — Filtering and search.

Useful curl techniques

Readable JSON in the terminal

curl outputs the response on a single line. To view it, pipe it through jq or python3 -m json.tool:

Terminal
curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals?limit=5" | jq
curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals?limit=5" | python3 -m json.tool

`-s` vs `-sS` in scripts

The -s flag (silent mode) suppresses the progress indicator along with network error messages — for example, Could not resolve host. In scripts this hides real failures. The -sS flag suppresses only the progress indicator, while the error text is written to stderr:

Terminal
# Silent, but on a network error the script silently gets an empty response
curl -s "$VIBE_URL/v1/deals" -H "X-Api-Key: $VIBE_API_KEY"

# Silent for normal operation, network errors are visible
curl -sS "$VIBE_URL/v1/deals" -H "X-Api-Key: $VIBE_API_KEY"

In shell scripts use -sS: network errors go to stderr and won't be lost during debugging.

A large request body via `--data-binary @file.json`

With a long body (a batch of 50 operations, an OpenAPI import, an expanded filter) the -d flag can't handle shell quote escaping and line breaks. Save the body to a file and pass it via @:

Terminal
cat > body.json <<'EOF'
{
  "calls": [
    { "id": "newDeals", "entity": "deals", "action": "list",
      "params": { "filter": { "stageId": "NEW" }, "limit": 100 } },
    { "id": "user", "entity": "users", "action": "get", "entityId": 1 }
  ]
}
EOF

curl -X POST "$VIBE_URL/v1/batch" \
  -H "X-Api-Key: $VIBE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @body.json

--data-binary preserves line breaks and quotes as-is, unlike -d, which strips out \n.

The response groups results by the id of each call — results holds the data, meta holds pagination statistics, summary holds the totals for the whole batch:

JSON
{
  "success": true,
  "data": {
    "results": {
      "newDeals": [ { "id": 7720, "title": "Server delivery", "stageId": "NEW" } ],
      "user": { "id": 1, "name": "John Brown" }
    },
    "totals": { "newDeals": 311 },
    "meta": {
      "newDeals": { "total": 311, "returned": 100, "hasMore": true }
    },
    "errors": [],
    "summary": { "total": 2, "succeeded": 2, "failed": 0 }
  }
}

Full batch rules (the limit of 50 calls, the cost in rate-limit units, the behavior of action: "list" with limit > 50) — Batch API.

Exporting a key without saving it in shell history

The export VIBE_API_KEY="vibe_api_..." command will be saved to ~/.zsh_history or ~/.bash_history — from there the key can end up on a screen share or in a system backup. An alternative is read -s: the shell reads the key without displaying it on screen, and only the read command remains in history, without the value.

Terminal
read -s VIBE_API_KEY && export VIBE_API_KEY
# the cursor doesn't move, paste the key, press Enter

The same technique works for VIBE_APP_KEY and VIBE_SESSION_TOKEN.

Headers and response code

Terminal
# -i — headers + body
curl -i -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me"

# -w — only selected statistics fields (code, time)
curl -s -o /dev/null -w "HTTP %{http_code}, %{time_total}s\n" \
  -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/deals"

Request limits

The response headers carry X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset — the current remaining request limit for the key:

Terminal
curl -s -D - -o /dev/null -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/me" | grep -i ratelimit

Saving the response to a file

Terminal
curl -s -H "X-Api-Key: $VIBE_API_KEY" "$VIBE_URL/v1/openapi.json" -o openapi.json

OpenAPI specification

The full machine-readable catalog of endpoints — /v1/openapi.json in OpenAPI 3.1 format:

Terminal
curl -s "$VIBE_URL/v1/openapi.json" -o openapi.json

The file imports into Postman, Insomnia, Swagger UI, and any tools that support OpenAPI 3.1. Based on the specification you can generate client libraries (openapi-generator, oazapfts, and similar). A tool that reads 3.0 only will not accept this specification: nullable values in it are described as a union of types (["number","null"]), a form introduced in 3.1.

Per-scope slice

The ?scope=<scope> parameter returns the specification narrowed down to the entities of a single scope — service and meta endpoints stay in every slice. The file comes out many times smaller than the full one, which helps when a tool or a model works with a single section:

Terminal
curl -s "$VIBE_URL/v1/openapi.json?scope=crm" -o openapi-crm.json

Exactly one known scope from the Scopes list is accepted. An unknown value and an empty string return the full specification rather than an error. A comma-separated list does the same — unless every listed value collapses to a single scope (task,tasks), in which case the slice is returned.

The `openapi-to-cli` utility

A third-party tool, not part of the Vibecode API. The platform does not monitor its availability. For updates, bugs, and compatibility with the specification, contact the author's repository.

openapi-to-cli is a CLI utility that builds commands from any OpenAPI specification. It connects to the Vibecode API without code generation: you provide the specification URL and the authorization header.

Terminal
npm install -g openapi-to-cli

ocli profile add vibecode \
  --spec https://vibecode.bitrix24.com/v1/openapi.json \
  --base-url https://vibecode.bitrix24.com \
  --header "X-Api-Key: $VIBE_API_KEY"

# Search for an endpoint by word
ocli vibecode search "deals"

# Call
ocli vibecode exec GET /v1/deals
ocli vibecode exec POST /v1/deals \
  --body '{ "title": "New deal", "stageId": "NEW", "categoryId": 0 }'

The utility is third-party, maintained by its author — for updates and bugs contact its repository. After changes in the Vibecode API, the updated specification is picked up by ocli on the next run.

PHP

A minimal template for scripts and server-side integrations — no external dependencies, only the built-in curl. The same template works for all endpoints: vibeRequest($url, $method, $data).

php
<?php

$VIBE_URL = getenv('VIBE_URL') ?: 'https://vibecode.bitrix24.com';
$VIBE_API_KEY = getenv('VIBE_API_KEY') ?: 'vibe_api_xxx...';

function vibeRequest(string $url, string $method = 'GET', ?array $data = null): array {
    global $VIBE_API_KEY;

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_HTTPHEADER     => [
            'X-Api-Key: ' . $VIBE_API_KEY,
            'Content-Type: application/json',
        ],
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // DELETE returns 204 with an empty body
    if ($httpCode === 204) {
        return ['success' => true];
    }

    $body = json_decode($response, true);
    if ($body === null) {
        throw new RuntimeException("HTTP $httpCode: malformed JSON in response");
    }
    if (empty($body['success'])) {
        $code = $body['error']['code'] ?? 'UNKNOWN';
        $msg  = $body['error']['message'] ?? 'Unknown error';
        throw new RuntimeException("$code: $msg (HTTP $httpCode)");
    }
    return $body;
}

Usage examples

php
// List
$result = vibeRequest("$VIBE_URL/v1/deals?limit=20");
foreach ($result['data'] as $deal) {
    echo $deal['id'] . ': ' . $deal['title'] . PHP_EOL;
}

// Create
$result = vibeRequest("$VIBE_URL/v1/deals", 'POST', [
    'title'      => 'Server delivery',
    'stageId'    => 'NEW',
    'categoryId' => 0,
    'amount'     => 1500000,
    'currency'   => 'USD',
]);
$dealId = $result['data']['id'];

// Search with a filter
$result = vibeRequest("$VIBE_URL/v1/deals/search", 'POST', [
    'filter' => [
        'stageId' => ['$ne' => 'LOST'],
        'amount'  => ['$gte' => 100000],
    ],
    'sort'  => ['createdAt' => 'desc'],
    'limit' => 50,
]);

// Delete — inside vibeRequest a 204 turns into ['success' => true]
vibeRequest("$VIBE_URL/v1/deals/$dealId", 'DELETE');

Full request body formats and response fields are on the pages for specific entities, for example Deals.

Error handling

On failure the response body has the form { success: false, error: { code, message } } and the corresponding HTTP status. Example — a request without a key:

Terminal
curl -i "$VIBE_URL/v1/deals"
HTTP/2 401
content-type: application/json; charset=utf-8

{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key required. Pass via X-Api-Key header."
  }
}

The full reference of codes and recommended actions — Error codes.