Developers › API reference › AI
POST /api/v1/commands/{id}/execute
Execute the previewed plan (X-Vestoris-Confirm: the preview token; "typed" for large or destructive plans).
- Scope
commands:execute - Idempotency-Key
- Confirmation
- operationId
aiExecute
Executes a previewed natural-language command. Send the preview's confirm_token in X-Vestoris-Confirm; for large or destructive plans add the typed phrase the preview shows: X-Vestoris-Confirm: <confirm_token>; typed="CONFIRM 3". Each item then goes through the normal services, which check permissions and compliance again; the answer lists each item's result. If the data changed since the preview, nothing runs and you get 412 with a new preview. Needs the commands:execute scope.
The token needs the scope commands:execute, and the person or service account behind it needs the matching privileges and account permissions, exactly as on the screens. See Scopes.
Idempotency-Key. Send a unique Idempotency-Key (up to 255 characters, e.g. a UUID) with every POST. Retrying with the same key and body replays the first answer for 24 hours, so a timeout never creates a second order; the same key with a different body is refused (idempotency_key_reused).
Confirmation. Needs X-Vestoris-Confirm with the confirm_token of the preview you are confirming (see Confirmations). The token is bound to that exact preview; if anything changed, ask for a new preview.
Request
POST /api/v1/commands/{id}/execute
Path parameters
| Name | Description | Example |
|---|---|---|
id | The id of the command. | 55 |
Headers
| Header | Required | Value |
|---|---|---|
Authorization | yes | Bearer <token>: an OAuth access token (vat_…) or a personal access token (vpt_…). Get a token |
Idempotency-Key | yes | A unique string up to 255 characters (a UUID). Idempotency |
X-Vestoris-Confirm | yes | The confirm_token of the preview you confirm, plus ; typed="CONFIRM n" for large or destructive plans. Confirmations |
Content-Type | yes | application/json |
Body: CommandExecute
No fields.
Other fields of the resource are accepted too; unknown fields are reported by a validation problem, never ignored silently.
Decimals (money, prices, quantities, percentages) are sent as strings, ids as strings, times as ISO 8601 UTC.
Examples
Keep the token in an environment variable (VESTORIS_TOKEN), never in the script.
curl
curl -X POST "https://vestoris.com/api/v1/commands/55/execute" \
-H "Authorization: Bearer $VESTORIS_TOKEN" \
-H 'Idempotency-Key: 7f9c2b1e-4d0a-4a7e-9a51-3c2f0b8d6e11' \
-H 'X-Vestoris-Confirm: vcf_c41e…; typed="CONFIRM 3"' \
-H "Content-Type: application/json" \
-d '{}'
Python (requests)
import os, requests
r = requests.post(
"https://vestoris.com/api/v1/commands/55/execute",
headers={
"Authorization": f"Bearer {os.environ['VESTORIS_TOKEN']}",
"Idempotency-Key": "7f9c2b1e-4d0a-4a7e-9a51-3c2f0b8d6e11",
"X-Vestoris-Confirm": "vcf_c41e…; typed=\"CONFIRM 3\"",
},
json={},
timeout=30,
)
r.raise_for_status() # errors are application/problem+json with a stable "code"
print(r.json())
JavaScript (fetch)
const res = await fetch("https://vestoris.com/api/v1/commands/55/execute", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VESTORIS_TOKEN}`,
"Idempotency-Key": "7f9c2b1e-4d0a-4a7e-9a51-3c2f0b8d6e11",
"X-Vestoris-Confirm": "vcf_c41e…; typed=\"CONFIRM 3\"",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.code}: ${data.detail}`); // problem+json
console.log(data);
Response
200 OK, application/json: Command. Rate-limit headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset.
Response fields
| Field | Type | Description |
|---|---|---|
id | id (string) | The record's id (a string of digits). |
screen | string | The screen the command is for: portfolio, blotter, monitor or wfrules. |
text | string | The command in the user's words. |
status | string | planned, question, previewed, executed, cancelled, stale or failed. |
planned_by_ai | boolean | Planned by ai. |
question | string or null | A clarifying question, when something material is ambiguous. |
message | string | What Vestoris says about the plan. |
plan | object | The typed actions the command was planned as. |
preview | object or null | What would happen: each item before and after, what is left out and why. |
item_count | integer | How many items the plan touches. |
confirm_token | string or null | Send this in X-Vestoris-Confirm to confirm exactly what was previewed. |
typed_confirmation | string or null | Text to send as "typed" for large or destructive plans. |
results | list | Each item's result. |
created_at | date-time or null | When it was created. |
previewed_at | date-time or null | When the preview was made. |
executed_at | date-time or null | When the plan was executed. |
Example response
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "1042",
"screen": "blotter",
"text": "Cancel all my unfilled AAPL buys",
"status": "previewed",
"planned_by_ai": true,
"question": null,
"message": "3 orders would be cancelled; 1 is left out (already filled).",
"plan": {
"actions": [
{
"type": "cancel_orders",
"filter": {
"side": "buy",
"symbols": [
"AAPL"
],
"mine": true
}
}
]
},
"preview": null,
"item_count": 3,
"confirm_token": "vcf_8a1c…",
"typed_confirmation": "CONFIRM 3",
"results": [],
"created_at": "2026-10-27T14:30:00Z",
"previewed_at": null,
"executed_at": null
}
Example values. Your values depend on your firm's data; prices, orders and fills are simulated.
Status codes and errors
Errors are application/problem+json (RFC 9457) with a stable code to program against; the detail says what to fix. See Errors.
| Status | When | Problem codes |
|---|---|---|
| 200 | Success | |
| 200 / 201 | The same Idempotency-Key again: the first answer is replayed (24 hours) | |
| 400 | The request is malformed | invalid_request invalid_json |
| 401 | No token, or it is invalid or expired | invalid_token |
| 403 | The token lacks the scope, or the person or service account behind it lacks the privilege or account permission | insufficient_scope forbidden ip_not_allowed |
| 404 | Not found, or not visible to you (the API never confirms what you may not see) | not_found |
| 409 | Not possible in the current state | invalid_transition conflict idempotency_in_progress |
| 422 | Validation failed (the detail says which field), or blocked | validation_failed idempotency_key_reused |
| 428 | A required header is missing | idempotency_key_required confirmation_required |
| 429 | Rate limited: wait for Retry-After seconds | rate_limited |
{
"type": "https://vestoris.com/developers/errors#validation_failed",
"title": "Validation failed",
"status": 422,
"detail": "Quantity must be greater than zero.",
"code": "validation_failed",
"instance": "/api/v1/commands/55/execute"
}
On the screens
The same thing in the app is explained in: