Skip to content
Voidex
Developers

Build on controlled execution

A versioned REST API, an OpenAPI 3.1 description, a TypeScript SDK and an MCP endpoint, all on the same lifecycle.

Concepts

  • Tool — a versioned contract: input schema, operation, risk class (read, low_write, sensitive_write, high_impact), reversibility, idempotency and default postconditions.
  • Connected account — credentials for one system in one environment (test, sandbox, production). Secrets are write-only.
  • Run — a single action or a workflow execution. Statuses: queued, running, awaiting_approval, blocked, succeeded, failed, needs_review, cancelled, timed_out.
  • Receipt — the evidence record for an attempted action, with outcome verified, verification_failed, inconclusive or unverified.

Authentication

Create a workspace API key in the console under Developer. Keys are shown once, stored only as hashes, scoped to permissions you hold, optionally expiring, and revoked automatically if their creator leaves the organization. API keys cannot approve actions.

curl https://api.voidex.net/api/v1/tools \
  -H "Authorization: Bearer $VOIDEX_API_KEY"

Submit a task

curl -X POST https://api.voidex.net/api/v1/runs \
  -H "Authorization: Bearer $VOIDEX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-8812" \
  -d '{
    "kind": "action",
    "tool": "acme_crm.create_deal",
    "connectedAccountId": "acct_…",
    "environment": "test",
    "input": { "name": "Renewal", "amount": 1200, "currency": "USD" }
  }'
# 202 {"runId":"run_…","status":"queued","approvalRequired":false,…}

Reusing an idempotency key with the same payload returns the original run; with a different payload it returns 409 idempotency_conflict.

Handle “approval required”

# 202 {"runId":"run_…","status":"awaiting_approval","approvalRequired":true,"approvalRequestId":"apr_…"}
# A person with the approver role decides in the console (or via POST /api/v1/approvals/:id/approve
# with the bindingHash they reviewed). Any payload change invalidates the approval.

Status and receipt

curl https://api.voidex.net/api/v1/runs/run_… -H "Authorization: Bearer $VOIDEX_API_KEY"
curl https://api.voidex.net/api/v1/runs/run_…/receipt -H "Authorization: Bearer $VOIDEX_API_KEY"
# {"latest":{"outcome":"verified","checks":[{"type":"record_exists","status":"passed"},…],"hash":"…","prevHash":"…"}}

TypeScript SDK

import { VoidexClient } from '@voidex/sdk';

const voidex = new VoidexClient({ baseUrl: 'https://api.voidex.net', apiKey: process.env.VOIDEX_API_KEY! });
const { runId, approvalRequired } = await voidex.submitAction({
  tool: 'acme_crm.create_deal',
  connectedAccountId: 'acct_…',
  input: { name: 'Renewal', amount: 1200, currency: 'USD' },
  idempotencyKey: 'order-8812',
});
const run = await voidex.waitForRun(runId);
const { latest } = await voidex.getReceipts(runId);
console.log(latest.outcome, latest.checks);

The SDK lives in packages/sdk of the repository. A Python SDK is not available.

Errors

{ "error": { "code": "policy_denied", "message": "…", "correlationId": "cor_…", "retryable": false, "details": {…} } }

Webhooks

Events: run.succeeded, run.failed, run.needs_review, run.blocked, approval.requested, approval.resolved, receipt.issued, benchmark.completed. Each delivery carries voidex-signature: t=…,v1=… (HMAC-SHA256 over t.body) and voidex-event-id for deduplication. Reject signatures older than five minutes.

import { verifyWebhook } from '@voidex/sdk';
if (!verifyWebhook(secret, req.headers['voidex-signature'], rawBody)) return res.status(400).end();

MCP

Point an MCP client at https://api.voidex.net/api/v1/mcp (streamable HTTP) with your API key as a bearer token. Tools appear as connector__action. MCP is a transport only: policy, approvals and verification still apply, and tool output returned to your agent is data, never instructions to Voidex.