REST API · v1 stable

OpenAPI 3.1. Signed. Idempotent. Versioned.

Use the SDK when it fits, the REST surface when it doesn’t. Either way you get the same auth, idempotency, signed-webhook, and tenant-isolation guarantees — and a machine-readable spec you can vendor into your CI.

Routes
180
Spec
OAS 3.1
Webhook sig
BLAKE3
Idempotency
24 h
api.radmah.ai / v1 / synthesize / jobsopenapi 3.1
POST/v1/synthesize/jobs
X-API-Key:          slt_live_AbCdEfGh…
X-Idempotency-Key:  8e0c…b21
Content-Type:       application/json

{
  "dataset_id": "ds_4a7c81",
  "model":      "synthesize",
  "rows":       10000,
  "seed":       42
}
202Accepted
X-Job-Id:                job_9b3df1
X-Rate-Limit-Remaining:  47
Retry-After:             —

{
  "job_id":     "job_9b3df1",
  "status":     "queued",
  "estimate":   { "credits": 14, "seconds": 38 },
  "evidence":   { "expected_root_pending": true },
  "_links":     {
    "self":     "/v1/synthesize/jobs/job_9b3df1",
    "stream":   "/v1/synthesize/jobs/job_9b3df1/events",
    "cancel":   "/v1/synthesize/jobs/job_9b3df1:cancel"
  }
}

Six things every endpoint guarantees.

rule · 01

OpenAPI 3.1, machine-readable

The schema that drives the SDK is generator-ready — customers with API access vendor it into their CI to auto-generate clients.

rule · 02

Scoped auth

JWT for end-users, API keys for service-to-service. Read / generate / admin scopes.

Idempotency built in

Idempotency-Key header stored 24 h; safe retry on transient 5xx without duplicate work.

Per-tenant + per-route limits

Token-bucket per tenant + per route, returns 429 with Retry-After and reset hint.

Signed webhooks

HMAC-SHA256 signature header + per-tenant rolling key + 5-minute replay window.

Versioned, deprecation-aware

v1 stable, deprecations announced 90 days in advance; X-Sunset header on retired routes.

Webhooks

Signed by default. Replay-window enforced.

Every webhook payload is HMAC-SHA256-signed with a rolling per-tenant key and a timestamp. Verify with one helper, ignore the noise of unauth’d traffic.

job.synthesize.completed
5 min replay window
  1. 01
    SLT signs payload
    BLAKE3(payload || ts || rolling_key)
  2. 02
    Webhook delivered
    POST your endpoint with headers
  3. 03
    You verify
    verify(payload, sig, key)
  4. 04
    Process if ok, 401 if not
    no signature → reject silently
X-SLT-Signature: blake3=2d4a8f… ts=1718834012
X-SLT-Event: job.synthesize.completed
Route groups

Nine groups. One contract.

Datasets

POST /v1/datasets/upload

Upload, browse, profile, delete.

Mock

POST /v1/mock/jobs

Schema-from-prompt synthesis.

Synthesize

POST /v1/synthesize/jobs

Training and generation jobs.

Agent

POST /v1/agent/projects

Autonomous agent runs with cost gates.

SCADA

POST /v1/scada/runs

Virtual SCADA telemetry runs.

ICS

POST /v1/ics/scenarios

Attack-mix scenario execution.

Connectors

POST /v1/connectors/{id}/browse

Browse + import from 14 source types.

Evidence

GET  /v1/evidence/{job_id}

Sealed bundle download + offline verify hint.

Webhooks

POST /v1/webhooks

Subscribe to events, signed payloads.

Stable error envelope. No surprises.

400Validation

Body fails JSON-Schema check; per-field error array returned.

401Auth missing

No JWT / API key; or token expired.

403Scope denied

Token authenticated but lacks the required scope.

404Not found

Resource not found within the calling tenant.

409Idempotent replay

Same Idempotency-Key seen with different body.

429Rate-limited

Returns Retry-After + per-route reset window.

500Internal

Always JSON, never HTML; correlation ID for support.

503Degraded

Dependency timeout; safe to retry on idempotent verbs.

Posture & auditability.

TLS 1.2+ only

HSTS on every response; older suites refused at the LB.

Tenant isolation

JWT carries tenant_id; ORM filter applied on every query.

Audit log

Every write recorded with caller, scope, and BLAKE3 of body.

Stable error envelope

Every error returns {error, code, correlation_id, hint}.

Try it on a sandbox tenant.

We spin a short-lived sandbox API key against demo data so you can wire the contract test runner into your CI before any procurement conversation.

api.radmah.ai / v1 / synthesize / jobsopenapi 3.1
POST/v1/synthesize/jobs
X-API-Key:          slt_live_AbCdEfGh…
X-Idempotency-Key:  8e0c…b21
Content-Type:       application/json

{
  "dataset_id": "ds_4a7c81",
  "model":      "synthesize",
  "rows":       10000,
  "seed":       42
}
202Accepted
X-Job-Id:                job_9b3df1
X-Rate-Limit-Remaining:  47
Retry-After:             —

{
  "job_id":     "job_9b3df1",
  "status":     "queued",
  "estimate":   { "credits": 14, "seconds": 38 },
  "evidence":   { "expected_root_pending": true },
  "_links":     {
    "self":     "/v1/synthesize/jobs/job_9b3df1",
    "stream":   "/v1/synthesize/jobs/job_9b3df1/events",
    "cancel":   "/v1/synthesize/jobs/job_9b3df1:cancel"
  }
}