لوكلاء AI: ملف markdown لهذه الصفحة — /docs-content-en/applications/solution-call-result.md فهرس التوثيق — /llms.txt

مقالات التوثيق متاحة حاليًا باللغة الإنجليزية فقط.

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 takes care of delivering 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.

Parameters

Parameter Type Required Description
ParametercallId (path) Typestring Requiredyes DescriptionCall id from X-Vibe-Call-Id. It is simpler to take the ready-made address from X-Vibe-Reply-Url
ParameterAuthorization (header) Typestring Requiredyes DescriptionBearer with the vcr_… reply token from X-Vibe-Reply-Token of the same call. The token is not valid for any other address

A platform key vibe_… is not accepted on this route.

Request fields (body)

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

Field Type Required Description
Fieldoutcome Typestring Requiredyes Descriptioncompleted — the method succeeded, failed — the method ended with an error
Fieldresult Typeobject Requiredwith completed DescriptionThe 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
Fielderror Typeobject Requiredno DescriptionWith failed — the error description. An empty object is allowed too: the call still closes as failed
Fielderror.code Typestring Requiredno DescriptionThe solution's error code matching [A-Z0-9_]{1,64}. A value that does not match the pattern is dropped
Fielderror.message Typestring Requiredno DescriptionHuman-readable text, up to 500 characters. Longer text is truncated
Fielderror.problem Typeobject Requiredno DescriptionDetails 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 vcr_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
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata.state Typestring DescriptionThe 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 is present only when the size limit is exceeded. A 409 SOLUTION_CALL_CLOSED carries the error.state field instead — the call state.

Errors

HTTP Code Description
HTTP401 CodeREPLY_TOKEN_INVALID DescriptionAuthorization has no Bearer with a token of the form vcr_…, including when a platform key is passed instead
HTTP401 CodeREPLY_TOKEN_INVALID DescriptionThe token matches no call: a token from another call, a non-existent callId, or the call has already been removed from the platform after its retention period. Whether the callId exists is not disclosed
HTTP409 CodeSOLUTION_CALL_CLOSED DescriptionThe call is already closed; error.state carries its state: completed, failed, canceled or expired
HTTP409 CodeSOLUTION_CALL_CLOSED Descriptionerror.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
HTTP422 CodeRESULT_INVALID Descriptionerror.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
HTTP422 CodeRESULT_INVALID Descriptionerror.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.

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
HeaderPrefer What it carriesrespond-async — the platform does not wait for the result in the response to this request
HeaderX-Vibe-Call-Id What it carriesCall id of the form call_…. The same id is part of the reply address
HeaderX-Vibe-Reply-Url What it carriesThe 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
HeaderX-Vibe-Reply-Token What it carriesReply token of the form vcr_… — the only way to authenticate the result. Issued for one call
HeaderX-Vibe-Reply-Deadline What it carriesDeadline 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 reply headers exist only on a contract call. When a business process action calls the solution through the application external API, X-Vibe-Reply-Url, X-Vibe-Reply-Token and X-Vibe-Reply-Deadline do not arrive. There the action sends the X-Bitrix24-Event-Token header, and the solution sends the result as a process event through POST /v1/workflows/event. The {$request.header.X-Vibe-Reply-Url} expression in the contract's callbacks.result refers to a header on this path. The result schema under it is shared by both channels: on the external API channel, returnValues is built from it. For the requirements for the key that sends the process event and a ready-made handler, see A long-running method in a business process.

The solution can answer such a call in two ways:

Solution response What happens
Solution response202 What happensThe 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
Solution response200 with a body in the form of this route What happensThe 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. Any other response (5xx, 3xx, 2xx other than 200 and 202), a dropped connection or a timeout is treated by the platform as a transient failure. It retries the delivery at increasing intervals 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 unconditionally.

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 in 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