Ways to run
The API
Submit a claim, have a person approve the plan, start the run, read the decision and re-check after a fix, over HTTP.
- Outcome
- You can start a check from your own code and read the decision with its evidence.
- Does not do
- An API key cannot approve a plan: every key gets 403 plan_requires_human and the link a person opens.
Authenticate with an API key, POST a deployment and a claim, send the approve_url to a person, resubmit with the approved plan id to start the run, then poll until a decision lands. After a fix, re-check the same plan. Base URL is https://vraelis.com.
Authenticate
Every request carries your key in the x-api-key header. Keys are created in the app, shown once, and stored only as a hash. Launching or re-checking needs a key with launch access, because it spends. Create an API key
Submit the claim
# 1. Submit the claim. Vraelis writes a plan and asks a person to approve it before anything runs.
curl -X POST https://vraelis.com/api/v1/verifications \
-H "x-api-key: $VRAELIS_API_KEY" \
-H "content-type: application/json" \
-H "idempotency-key: $(uuidgen)" \
-d '{
"deployment_url": "https://staging.example.com",
"claim": "A customer can upgrade to Pro and still have access after signing in again."
}'Returns 202 with state: "review_required", the derived requirements, the plan to approve, and the approve_url a person opens. No run started, nothing charged, and no verification id yet. The response also carries contract_id and contract_version.
{
"state": "review_required",
"review_required": true,
"claim": "A customer can upgrade to Pro and still have access after signing in again.",
"requirements": [
"Upgrading to Pro grants Pro access immediately",
"Pro access is still present after signing out and back in"
],
"reviewed_plan_id": "rvp_3c9e26ef",
"reviewed_plan_expires_at": "2026-09-28T19:04:11.000Z",
"approve_url": "https://app.vraelis.com/review/rvp_3c9e26ef",
"human_reviewed": false,
"message": "Vraelis built a plan that can prove this claim, and no person has reviewed it yet. A person approves it at approve_url; then resubmit with reviewed_plan_id to run exactly what was approved. Nothing was run and nothing was charged."
}Approve, then start the run
Only a signed-in person approves a plan, with one click at the approve_url. The approval is its own recorded event: who approved which plan, and when. Every API key is refused with 403 plan_requires_human and the same link, so the tool that asked for the check can never sign off on it. The run then executes exactly the approved plan, with no re-derivation.
# 2. A person opens approve_url and approves the plan with one click. A key cannot: curl -X POST https://vraelis.com/api/v1/verifications/plans/rvp_3c9e26ef/approve \ -H "x-api-key: $VRAELIS_API_KEY" # -> 403 { "error": { "code": "plan_requires_human", ... }, # "approve_url": "https://app.vraelis.com/review/rvp_3c9e26ef" } # While you wait for the person, read the plan. approve_url is present while it is pending. curl https://vraelis.com/api/v1/verifications/plans/rvp_3c9e26ef \ -H "x-api-key: $VRAELIS_API_KEY" # -> { "reviewed_plan_id": "rvp_3c9e26ef", "approval_state": "pending", # "approve_url": "https://app.vraelis.com/review/rvp_3c9e26ef", ... } # 3. Once approval_state reads "approved", resubmit the SAME deployment and claim with the plan id. # This is the call that starts a run, and the first response that carries a verification_id. curl -X POST https://vraelis.com/api/v1/verifications \ -H "x-api-key: $VRAELIS_API_KEY" \ -H "content-type: application/json" \ -d '{ "deployment_url": "https://staging.example.com", "claim": "A customer can upgrade to Pro and still have access after signing in again.", "reviewed_plan_id": "rvp_3c9e26ef" }' # -> { "verification_id": "vrf_9c1e0f2a41", "state": "running", # "status_url": "/v1/verifications/vrf_9c1e0f2a41", "human_reviewed": true }
Read the decision
Poll GET /v1/verifications/{id}. While running, the body is just the id and state. Once complete, decision is one of verified, failed, or blocked. recheck_of names the verification a re-check repeated, or is null.
# 4. Poll until a decision lands. While the run is going, there is no decision yet.
curl https://vraelis.com/api/v1/verifications/vrf_9c1e0f2a41 \
-H "x-api-key: $VRAELIS_API_KEY"{
"verification_id": "vrf_9c1e0f2a41",
"state": "completed",
"decision": "failed",
"claim": "A customer can upgrade to Pro and still have access after signing in again.",
"requirements": [
"Upgrading to Pro grants Pro access immediately",
"Pro access is still present after signing out and back in"
],
"failures": [
{
"severity": "critical",
"title": "Pro access is lost after signing back in",
"expected": "The account still shows Pro after re-authenticating",
"observed": "The account reverted to the Free plan",
"reproduce": ["Upgrade to Pro", "Sign out", "Sign back in", "Open billing"]
}
],
"evidence": [
{ "checking": "Upgrade to Pro", "result": "passed", "failed_at_step": null },
{ "checking": "Access persists after re-auth", "result": "failed", "failed_at_step": 3 }
],
"repair_prompt": "Pro entitlement is not re-read on session restore. On sign-in, load the subscription from the source of truth before rendering plan state, and confirm Pro survives a full sign-out and sign-in.",
"console_url": "https://app.vraelis.com/systems/app_5b7d/passes/9c1e0f2a41",
"reviewed_plan_id": "rvp_3c9e26ef",
"recheck_of": null,
"human_reviewed": true
}Re-check after a fix
After a Failed, deploy the fix and call POST /v1/verifications/{id}/recheck. It runs every journey of the same approved plan again and returns a new verification id; the earlier record is never touched. No new approval is needed within 24 hours of the approval, for at most 10 re-checks, on the same scheme and host. An optional deployment_url may name another path on that same site. Past those limits the API answers recheck_window_closed or recheck_limit_reached, and you start a new verification. Each re-check is billed as one verification.
# 5. Deploy the fix, then run the same approved plan again. No new approval inside the window.
curl -X POST https://vraelis.com/api/v1/verifications/vrf_9c1e0f2a41/recheck \
-H "x-api-key: $VRAELIS_API_KEY"{
"verification_id": "vrf_4be27d9c10",
"state": "running",
"status_url": "/v1/verifications/vrf_4be27d9c10",
"recheck_of": "vrf_9c1e0f2a41",
"human_reviewed": true,
"reviewed_plan_id": "rvp_3c9e26ef",
"rechecks_left": 9,
"recheck_window_ends_at": "2026-09-29T18:04:11.000Z"
}Ask before you commit
A dry run derives the plan, checks it can actually prove the claim, and charges nothing. When it can, it mints the same plan a person approves in step 2 above, with its approve_url. When it cannot, it says so with a repair prompt, and there is nothing to approve.
# Ask "is this claim provable against this build?" before spending anything.
curl -X POST https://vraelis.com/api/v1/verifications \
-H "x-api-key: $VRAELIS_API_KEY" \
-H "content-type: application/json" \
-d '{ "deployment_url": "https://staging.example.com",
"claim": "A customer can upgrade to Pro and keep access after signing in again.",
"dry_run": true }'{
"dry_run": true,
"would_launch": true,
"requirements": ["Upgrading to Pro grants Pro access immediately", "..."],
"reviewed_plan_id": "rvp_3c9e26ef",
"reviewed_plan_expires_at": "2026-09-28T19:04:11.000Z",
"approval_required": true,
"approve_url": "https://app.vraelis.com/review/rvp_3c9e26ef",
"human_reviewed": false
}Requirements
Every response echoes the requirements Vraelis derived from your claim, and states whether a person approved them in human_reviewed. A model reading a claim can misread it; the requirements are what the person is approving, and they are how you catch a confidently wrong verdict before you trust it.
Idempotency
Send an idempotency-key header. A retry with the same key, deployment, and claim replays the original verification instead of starting and paying for a second one. The same key with a different claim is refused, so a changed request can never be answered with an earlier run.
{
"error": {
"code": "idempotency_key_reused",
"message": "That idempotency key was already used for a different verification. Use a new key, or resend the original request exactly.",
"request_id": "req_5f3a90"
}
}Errors
Errors share one envelope: { error: { code, message, request_id } }, with the id also on the X-Request-Id header. A claim that cannot be proven returns claim_not_provable (422) with a repair prompt, and nothing is charged.
What has shipped
We will not document an endpoint we have not shipped. These are the ones that answer today.
POST /api/v1/verifications, create, dry-run, or run an approved planGET /api/v1/verifications/plans/{id}, the plan, its approval state, andapprove_urlwhile it is pendingGET /api/v1/verifications/{id}, decision, evidence, repair prompt,recheck_ofPOST /api/v1/verifications/{id}/recheck, the same approved plan after a fixPOST /api/v1/verifications/plans/{id}/approve, for a signed-in person only; every API key gets403 plan_requires_human- The vraelis CLI:
verify,recheck,result,init,mcp - The MCP server, local (
vraelis mcp) and hosted (https://vraelis.com/mcp) - Signed
verification.completedwebhooks, and Slack delivery