YZ ajanları için: bu sayfanın markdown'ı — /docs-content-en/applications/solution-call-result.md dokümantasyon dizini — /llms.txt

Dokümantasyon makaleleri şu anda İngilizce olarak mevcuttur.

Deliver the result of a long-running method

POST /v1/solution-calls/:callId/result

Accepts the outcome of a long-running contract method call from the solution and itself delivers it to the Bitrix24 account. The solution receives the address of this route, a single-use reply token and the deadline as headers on the call itself, so it needs neither a platform key nor any extra setup.

How a long-running call arrives

The platform invokes a contract method with x-vibe-async: true the same way as a regular one: an HTTP request to the solution's route from the contract, through the application tunnel. Five headers set a long-running call apart:

Header What it carries
Prefer respond-async — the platform does not wait for the result in the response to this request
X-Vibe-Call-Id Call id of the form call_…. The same id is part of the reply address
X-Vibe-Reply-Url The ready-made address of this route with the callId filled in: https://vibecode.bitrix24.com/v1/solution-calls/call_…/result. Take the address from the header instead of building it yourself
X-Vibe-Reply-Token Reply token of the form vcr_… — the only way to authenticate the result. Issued for one call
X-Vibe-Reply-Deadline Deadline in RFC 3339 format, for example 2026-09-21T10:10:00.000Z. After it the call closes as expired and the result is no longer accepted

The common contract-call headers arrive here as well: X-Vibe-Request-Id, X-Vibe-Caller-Kind with the value contract, X-Vibe-Caller-Portal-Id, X-Vibe-Portal-User-Id, X-Vibe-Operation-Id, X-Vibe-Contract-Version and Idempotency-Key. The X-Vibe-Invocation-Context header is present only on a call that was made with a context. A contract call carries no X-Vibe-Caller-Key-Id or X-Vibe-Caller-App-Id — it does not go through an external API key.

The solution can answer such a call in two ways:

Solution response What happens
202 The platform treats the call as accepted and waits for the result on this route until the deadline from X-Vibe-Reply-Deadline. The response body is not read
200 with a body in the form of this route The result is accepted right away, without a separate request: the body goes through the same validation as on this route, and the call closes with the outcome completed or failed

A 4xx response closes the call as failed without a result — sending one later is pointless. Every other response — 5xx, 3xx, 2xx other than 200 and 202 — together with a dropped connection and a timeout the platform treats as a transient failure and retries the delivery with growing pauses until the deadline from X-Vibe-Reply-Deadline — with the same X-Vibe-Call-Id and the same reply token, so this route accepts a result computed on the first attempt without reservations.

Parameters

Parameter Type Required Description
callId (path) string yes Call id from X-Vibe-Call-Id. It is simpler to take the ready-made address from X-Vibe-Reply-Url

Authentication is the Authorization: Bearer header with the reply token from X-Vibe-Reply-Token of the same call. A platform key vibe_… is not accepted on this route, and the reply token opens no other address.

Request fields (body)

The body is JSON with one of two outcomes. The body size is up to 512 KiB, measured in raw bytes before parsing.

Field Type Required Description
outcome string yes completed — the method succeeded, failed — the method ended with an error
result object with completed The result per the callbacks.result schema of the contract version the call was accepted under. Publishing a new version after the call does not affect the validation
error object no With failed — the error description. An empty object is allowed too: the call still closes as failed
error.code string no The solution's error code matching [A-Z0-9_]{1,64}. A value off the pattern is dropped
error.message string no Human-readable text, up to 500 characters. The excess is cut off
error.problem object no Details per RFC 9457: type, title, detail, instance, each up to 500 characters. Other keys are dropped

Body with failed:

JSON
{
  "outcome": "failed",
  "error": {
    "code": "INVOICE_LOCKED",
    "message": "Invoice is locked by another user",
    "problem": {
      "type": "https://example.com/problems/invoice-locked",
      "title": "Invoice locked",
      "detail": "Invoice 17 is being edited",
      "instance": "/invoices/17"
    }
  }
}

Examples

The route has a single authorization axis — the reply token from X-Vibe-Reply-Token, so there is one example per language: a personal key and an application authorization key get 401 REPLY_TOKEN_INVALID.

curl — reply token

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/solution-calls/call_01M31PGZ80V9GJMWJ5N48AATB2/result" \
  -H "Authorization: Bearer YOUR_REPLY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"outcome": "completed", "result": {"invoiceNumber": "A-17"}}'

JavaScript — reply token

javascript
// Headers of the incoming call — from the long-running method handler in the solution.
const replyUrl = req.headers['x-vibe-reply-url'];
const replyToken = req.headers['x-vibe-reply-token'];

const res = await fetch(replyUrl, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${replyToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ outcome: 'completed', result: { invoiceNumber: 'A-17' } }),
});

const body = await res.json();
if (!body.success) {
  // A 4xx closes the call: retrying the same result is pointless.
  console.error(`result not accepted: ${body.error.code}`);
}

Response fields

Field Type Description
success boolean Always true on success
data.state string The state the call closed with: completed for outcome: completed, failed for outcome: failed

Response example

JSON
{
  "success": true,
  "data": {
    "state": "completed"
  }
}

Error response example

422 — the body is over 512 KiB, the call is closed as failed:

JSON
{
  "success": false,
  "error": {
    "code": "RESULT_INVALID",
    "message": "The result body is over the boundary-contract limit; the call is closed as failed",
    "errorCode": "SOLUTION_RESULT_TOO_LARGE",
    "limitBytes": 524288
  }
}

The error.errorCode field names the reason — SOLUTION_RESULT_TOO_LARGE or SOLUTION_BAD_RESPONSE — and the outcome reaches the Bitrix24 account with the same code. The error.limitBytes field comes only when the size is exceeded. A 409 SOLUTION_CALL_CLOSED carries the error.state field instead — the call state.

Errors

HTTP Code Description
401 REPLY_TOKEN_INVALID Authorization has no Bearer with a token of the form vcr_…, including when a platform key is passed instead
401 REPLY_TOKEN_INVALID The token matches no call: a foreign token, a non-existent callId, or the call has already been removed from the platform by its retention period. Whether the callId exists is not disclosed
409 SOLUTION_CALL_CLOSED The call is already closed; error.state carries its state: completed, failed, canceled or expired
409 SOLUTION_CALL_CLOSED error.state is accepted: the call is open but held by a previous attempt to deliver the result that did not finish. Retry later — the platform releases such a call within two minutes
422 RESULT_INVALID error.errorCode is SOLUTION_RESULT_TOO_LARGE: the body is over 512 KiB, error.limitBytes is the limit in bytes. The call is closed as failed
422 RESULT_INVALID error.errorCode is SOLUTION_BAD_RESPONSE: the body is not JSON, outcome is neither completed nor failed, result is missing with completed, or result does not pass the contract's callbacks.result schema. The call is closed as failed

Full list of common API errors — Errors.

Known specifics

  • Any 4xx closes the call for good. A 422 is not an invitation to fix the body and retry: the call has already moved to failed, the outcome with the reason code has gone to the Bitrix24 account, and the same token answers 409 from then on. Validate result against the callbacks.result schema before sending — a fix in the solution's code helps the next call, not this one.
  • Retry only after a 5xx or a dropped connection. The token is single-use per accepted outcome, not per attempt: until the platform has answered 2xx or 4xx, the result is not recorded, and a retry with the same address, token and body is mandatory — otherwise the step on the Bitrix24 account waits out the deadline and ends with a timeout. An unfinished attempt holds the call for one to two minutes, and during that time the answer is 409 with state: accepted.
  • The reply token is the secret of one call. Whoever holds it can close your call with any result. Do not write it to a log, do not show it in the interface and do not pass it on. The platform writes neither the token nor the result body to its own logs.
  • After the deadline or a cancellation the Bitrix24 account no longer needs the result. A 409 with state: expired or state: canceled is the signal to stop the long-running work: there is no point continuing it, and there is nowhere left to accept its outcome.
  • A 200 means "the outcome is recorded", not "the Bitrix24 account has received it". The platform handles the delivery to the Bitrix24 account itself, with retries while the account is unavailable. The solution does not need to do anything for that.

See also