APEX Developers

Quickstart

Goal: your first authenticated APEX call — a retrieval-augmented query against your tenant's corpus — in a few minutes, then the async patterns you will use everywhere else.

0. What you need (from onboarding)

Your platform operator provisions these during tenant onboarding:

Item Environment variable (suggested)
Tenant identifier (e.g. your-tenant) APEX_TENANT_ID
Tenant API key (apex_test_… for development) APEX_API_KEY
Machine-to-machine client id + secret + token URL + scopes APEX_CLIENT_ID, APEX_CLIENT_SECRET, APEX_TOKEN_URL
Base URLs for your environment see Environments & Endpoints

Development base URLs used below: https://zenith.dev.apex.reisiger.org (Zenith), https://vector.dev.apex.reisiger.org (Vector).

1. Mint an access token

See Authentication for the full flow. Short version (curl):

TOKEN=$(curl -s -X POST "$APEX_TOKEN_URL" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$APEX_CLIENT_ID&client_secret=$APEX_CLIENT_SECRET&scope=apex/your-tenant.read" \
  | python -c "import sys,json;print(json.load(sys.stdin)['access_token'])")

2. Confirm your tenant is live

curl -s "https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/config" \
  -H "Authorization: Bearer $TOKEN"

A 200 with your tenant's configuration view means you are onboarded. A 404 means the tenant is not configured for Zenith yet — that is the platform's fail-closed behaviour, not a transient error; contact your operator.

3. Your first knowledge query

PowerShell:

$headers = @{ Authorization = "Bearer $token"; 'X-Correlation-ID' = "quickstart:first-query" }
$body = @{ query = 'What are the safety requirements for pressure vessel inspections?'; mode = 'rag' } | ConvertTo-Json

Invoke-RestMethod -Method Post `
  -Uri 'https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/query' `
  -Headers $headers -ContentType 'application/json' -Body $body

curl:

curl -s -X POST "https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/query" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Correlation-ID: quickstart:first-query" \
  -d '{"query": "What are the safety requirements for pressure vessel inspections?", "mode": "rag"}'

Python:

import requests

resp = requests.post(
    "https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/query",
    headers={"Authorization": f"Bearer {token}", "X-Correlation-ID": "quickstart:first-query"},
    json={"query": "What are the safety requirements for pressure vessel inspections?", "mode": "rag"},
    timeout=60,
)
resp.raise_for_status()
result = resp.json()
print(result["data"]["answer"])
for source in result["data"]["sources"]:
    print(" cited:", source["document_id"], source["relevance_score"])
print("cost (ZAR):", result["cost"]["total_zar"])

Three things to notice in the response:

  1. data.sources — every answer carries citations back to corpus chunks. Surface them; they are your provenance story.
  2. data.verification — when enabled for your tenant, answers carry a verification block (confidence, claim checks).
  3. cost — per-call cost breakdown in ZAR. Thread your X-Correlation-ID and reconcile later — see Usage & Cost.

4. Verify a claim (tenant API key style)

Vector authenticates with your tenant API key directly and carries tenant as a query parameter:

curl -s -X POST "https://vector.dev.apex.reisiger.org/verify?tenant_id=your-tenant" \
  -H "Authorization: Bearer $APEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"claim": "The company holds ISO 9001 certification.", "context": "supplier due diligence", "depth": "standard"}'

The response contains a verdict (supported / contradicted / insufficient / mixed) and a calibrated confidence between 0 and 1.

5. The async pattern you will use everywhere

Long-running work (corpus ingestion, document jobs, message delivery) follows submit-then-poll:

# Submit — returns immediately with a job/message id
job = requests.post(
    "https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/ingest",
    headers={"Authorization": f"Bearer {token}"},
    json={},
    timeout=30,
).json()

# Poll until terminal
import time
while True:
    status = requests.get(
        f"https://zenith.dev.apex.reisiger.org/api/v1/your-tenant/ingest/{job['job_id']}",
        headers={"Authorization": f"Bearer {token}"},
        timeout=30,
    ).json()
    if status["status"] in ("completed", "failed"):
        break
    time.sleep(5)

The same shape applies to Document Operations jobs (GET /v1/jobs/{id}) and Echo message delivery (GET /messages/{tenant}/{message_id}), and Echo can push terminal status to you instead via signed webhooks — see Integration Conventions.

Where next