Developers
Invoke the verification engine from your own systems.
Send a deployment and a claim, get back an explainable decision with evidence. One call to start, one to read the result, and one exit code to gate a release on. Every shape below is copied from the shipped API.
One capability, exposed
Verification is one capability inside broader oversight.
Vraelis follows agent work from assigned responsibility to trusted completion. This API drives the part that is live and self-serve today: when something claims to be done, Vraelis proves the running software against the claim. The responsibility, memory, and agent-oversight APIs are direction, and are not documented here until they ship.
The API
Create a verification, read the decision.
Two calls. Authenticate with an API key, POST a deployment and a claim, then poll the status URL until a decision lands. Base URL is https://vraelis.com.
AuthEvery 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 a verification needs a key with launch access, because it spends.
# Create a verification: send the deployment and the claim.
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 the id, the derived requirements, and human_reviewed: false.
{
"verification_id": "vrf_9c1e0f2a41",
"state": "running",
"status_url": "/v1/verifications/vrf_9c1e0f2a41",
"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"
],
"human_reviewed": false
}ReadPoll GET /v1/verifications/{id}. While running, the body is just the id and state. Once complete, decision is one of verified, failed, or blocked.
# 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.",
"human_reviewed": false
}RequirementsEvery response echoes the requirements Vraelis derived from your claim, and states human_reviewed: false plainly. A model reading a claim can misread it; the requirements are how you catch a confidently wrong verdict before you trust it.
IdempotencySend 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 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.
Review before you spend
Put a human decision before a paid run.
A dry run synthesizes the plan, checks it can prove the claim, and charges nothing. When it can, it mints a reviewed plan you approve as a separate audited event. The paid run then executes exactly what was approved, and comes back marked human_reviewed.
# 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-07-24T19:04:11.000Z",
"approval_required": true,
"human_reviewed": false
}# 1. Approve the reviewed plan. A separate, audited event: holding the id is not approval.
curl -X POST https://vraelis.com/api/v1/verifications/plans/rvp_3c9e26ef/approve \
-H "x-api-key: $VRAELIS_API_KEY"
# -> { "reviewed_plan_id": "rvp_3c9e26ef", "approval_state": "approved", "already_approved": false }
# 2. Run exactly what was reviewed. The paid run consumes the approved plan verbatim.
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.",
"reviewed_plan_id": "rvp_3c9e26ef" }'
# -> the response carries "human_reviewed": trueCLI
One command. The exit code is the interface.
The vraelis CLI wraps the same endpoint for people and pipelines. In CI it is read by an if-statement far more often than by a person, so the exit code carries the verdict and everything else is decoration.
# One command. The exit code is the interface.
export VRAELIS_API_KEY="<your key>" # created at app.vraelis.com/api with "Launch runs" access
vraelis verify \
--url https://staging.example.com \
--claim "A customer can upgrade to Pro and keep access after signing in again" \
--wait
# 0 verified 1 failed 2 blocked or could not run
# --repair-prompt prints only the fix package, ready to paste into a coding agent- 0Verified. The claim held, with evidence.
- 1Failed. The claim did not hold; a repair prompt is attached.
- 2Blocked, or the tool could not run at all.
The CLI collapses “blocked” and “could not run” into 2, because a gate should treat “I could not check” the same as “no verdict.” A hand-rolled gate that polls the API can split those out, exiting 3 when no decision is reached in the window.
// gate.mjs: ship only on "verified". The exit code gates the deploy.
// 0 verified 1 failed 2 blocked 3 no decision reached
import { randomUUID } from "node:crypto";
const API = "https://vraelis.com/api/v1/verifications";
const headers = {
"content-type": "application/json",
"x-api-key": process.env.VRAELIS_API_KEY,
"idempotency-key": randomUUID(),
};
const created = await fetch(API, {
method: "POST",
headers,
body: JSON.stringify({ deployment_url: process.env.PREVIEW_URL, claim: process.env.VRAELIS_CLAIM }),
});
const { verification_id } = await created.json();
// While running, decision is absent; keep polling until it lands.
let decision = null, out;
for (let i = 0; i < 120 && decision === null; i++) {
await new Promise((r) => setTimeout(r, 5000));
out = await (await fetch(API + "/" + verification_id, { headers })).json();
decision = out.decision ?? null;
}
// Gate on the decision, never the run state. A finished run is not a pass.
switch (decision) {
case "verified": process.exit(0);
case "failed": process.exit(1);
case "blocked": process.exit(2);
default: process.exit(3); // no decision within the polling window
}Webhooks
Get the decision pushed to you.
Connect an endpoint and Vraelis POSTs a signed verification.completed event the moment a verification finalizes. It carries only owner-safe facts: the decision, flow counts, ids, and a link to the evidence. Never a session id, token, credential, or signed artifact URL.
EventOne event, verification.completed, delivered with the headers x-vraelis-event, x-vraelis-timestamp, and x-vraelis-signature.
{
"event": "verification.completed",
"run_id": "9c1e0f2a41",
"application_id": "app_5b7d",
"decision": "failed",
"flows_total": 4,
"flows_passed": 3,
"deployment_url": "https://staging.example.com",
"completed_at": "2026-07-24T18:04:11.220Z",
"report_url": "https://app.vraelis.com/systems/app_5b7d/passes/9c1e0f2a41"
}VerifyThe signature is an HMAC over the raw body prefixed with the timestamp, so recompute over the exact bytes you received before trusting the payload.
// Verify the delivery: HMAC-SHA256 over `${timestamp}.${rawBody}`.
import { createHmac, timingSafeEqual } from "node:crypto";
const timestamp = req.headers["x-vraelis-timestamp"];
const signature = req.headers["x-vraelis-signature"]; // "sha256=<hex>"
const expected = "sha256=" + createHmac("sha256", process.env.VRAELIS_SECRET_KEY)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const ok = Boolean(signature) && timingSafeEqual(Buffer.from(signature), Buffer.from(expected));Point the same endpoint at a Slack incoming webhook and the event arrives as a formatted message in your channel instead of raw JSON, with the decision, flows passed, and a link to the evidence.
Integrations
GitHub, Vercel, and Slack, from the same primitives.
Run the CLI in GitHub Actions to gate a deploy, point a verification at a Vercel preview or production URL, and route the result into Slack. Each one is the API, the CLI, or a webhook wired to a place you already work, not a separate product.
Honest about what is live
We will not document an endpoint we have not shipped.
Live today
- POST /api/v1/verifications, create, dry-run, or run a reviewed plan
- GET /api/v1/verifications/{id}, decision, evidence, repair prompt
- Reviewed-plan approval before a paid run
- The vraelis verify CLI and its CI exit codes
- Signed verification.completed webhooks
- GitHub Actions, Vercel deployment URLs, Slack
Direction
- Responsibility and assignment APIs
- Agent memory and reliability APIs
- Continuous agent-activity ingestion
- IDE, desktop, and MCP surfaces
These are where oversight is going. When one ships, it appears here with a real example you can run.
Wire the decision into the place you ship from.
Start a verification from CI, gate on the exit code, and get the evidence pushed back. One key, real endpoints, no dashboard to watch.