API v1

Veritas 360 Public Compliance API

Regulatory framework discovery and compliance document generation, over HTTPS with JSON.

Overview

The API exposes three capabilities of the Veritas 360 compliance engine:

1. Framework discovery

Send a plain-language query — "hospitals in Dubai", "financial services firms in Singapore" — and receive ranked candidate regulatory frameworks with regulator, jurisdiction, sector, source URL, confidence and reasoning.

2. Document generation

Request a policy or framework-reference document asynchronously: submit a job, poll its status, then download the finished document as json, md, pdf or docx.

3. Document library

Ingest your own compliance documents. Each document is AI-classified into your category structure, indexed, and instantly searchable with full-text relevance ranking and highlighted snippets.

Base URL: https://api.veritas360.com.au/api/public/v1

A machine-readable OpenAPI 3 document is available for client generation and testing tools.

Authentication

Every request (except the service card and the OpenAPI document) requires an API key issued by Kurateq. Keys look like v360_sk_… and are shown to you exactly once when issued — store them securely; only a hash is kept on our side.

Send the key in either header:

Authorization: Bearer v360_sk_...
# or
X-API-Key: v360_sk_...

A missing or invalid key returns 401 with a JSON error envelope. Repeated bad-key attempts from one address are temporarily blocked.

Lost or leaked key?

Contact your Kurateq account contact immediately. Keys can be rotated (new key issued, old one stops instantly) or disabled outright.

Sandbox & live mode

Every client starts in sandbox mode: all endpoints work end-to-end, but discovery and generation return clearly watermarked sample output and incur no processing cost. This lets you build and test your full integration safely.

When you're ready, Kurateq flips your key to live mode — same endpoints, same shapes, real results. Check your current mode any time with GET /ping.

Endpoints

EndpointDescription
GET/Service card and endpoint list (no auth)
GET/openapi.jsonOpenAPI 3 document (no auth)
GET/pingAuth check — returns your client name and current mode
GET/capabilitiesAvailable document types, output formats, and your key's limits
POST/frameworks/suggestFramework discovery. Body: {"query": "..."}
POST/documents/generateStart a generation job. Returns 202 with a jobId
POST/documents/mapMap your document against a verified framework's control set. JSON {"framework","content","title?"} or multipart file upload (field file, ≤10 MB — DOCX/PDF/Excel/PowerPoint/text). Returns 202 with a jobId; result includes coverage %, per-control evidence, and a gap list
GET/jobs/{jobId}Job status: queued → running → completed / failed
GET/documents/{jobId}?format=…Download the finished document or mapping report (json, md, pdf, docx)
POST/library/documentsIngest a document into your library. Body: {"title","content","category?","tags?","filename?"}. Returns 202 with a jobId and documentId
POST/library/documents/{id}/refreshReplace a library document's content with a new version (re-classified and re-indexed; version increments)
GET/libraryList your library documents plus storage counters
GET/library/documents/{id}One document's metadata; add ?include=content for the stored text
DELETE/library/documents/{id}Remove a document from your library (free)
POST/library/searchSynchronous full-text search. Body: {"query","category?","tags?","limit?"} → ranked results with highlighted snippets
GET/usageYour request and generation counters against your limits
GET/billingToken balance, per-operation prices, available credit packs, recent ledger
POST/billing/checkoutBuy a credit pack. Body: {"pack":"pack25"} → secure Stripe payment URL

Generation request body

FieldRequiredNotes
frameworkYesFramework or standard name (aliases: standard, name)
documentTypeNoDefaults to framework_reference; see /capabilities for the full list
jurisdictionNoe.g. "United Arab Emirates"
organisationNoObject: {name, sector, country} — personalises the document

Document library

Your library is a private, per-key store of your own compliance documents. Ingest is asynchronous (like generation): submit the document, poll the job, then it appears in listings and search. On live keys each document is AI-classified into your organisation's category structure with tags and a summary; on sandbox keys classification is watermarked but indexing and search are fully real.

RuleValue
Minimum document size200 characters
Maximum document size300,000 characters
Library capacity500 documents (live) / 25 (sandbox)
Duplicate contentRejected before any charge (duplicate_document) — use refresh to update an existing document
Library fullRejected before any charge (library_full) — delete documents to make room
# Ingest a document (async — poll the returned jobId)
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"title":"Incident Response Plan","content":"..."}' $BASE/library/documents
# → {"jobId":"...","documentId":"...","status":"queued", ...}

# Search it (synchronous)
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"incident response"}' $BASE/library/search

# Update a document with new content (version increments)
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"content":"..."}' $BASE/library/documents/<id>/refresh

# List / fetch / remove
curl -s -H "Authorization: Bearer $KEY" $BASE/library
curl -s -H "Authorization: Bearer $KEY" "$BASE/library/documents/<id>?include=content"
curl -s -X DELETE -H "Authorization: Bearer $KEY" $BASE/library/documents/<id>

If ingest or refresh fails after admission, the charge is automatically refunded — check the job's status for the reason. Listing, fetching and deleting are free; search is charged per query.

Quickstart (curl)

BASE=https://api.veritas360.com.au/api/public/v1
KEY=v360_sk_...        # issued by Kurateq

# 1. Am I alive, and what mode am I in?
curl -s -H "Authorization: Bearer $KEY" $BASE/ping

# 2. What can I do?
curl -s -H "Authorization: Bearer $KEY" $BASE/capabilities

# 3. Discover frameworks for a market
curl -s -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query": "hospitals in Dubai"}' $BASE/frameworks/suggest

# 4. Generate a document (async)
curl -s -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"documentType":"privacy","framework":"Dubai ISR",
       "jurisdiction":"United Arab Emirates",
       "organisation":{"name":"Acme Clinics DMCC","sector":"healthcare"}}' \
  $BASE/documents/generate
# → {"jobId":"...","status":"queued","poll":"/api/public/v1/jobs/...", ...}

# 5. Poll until completed
curl -s -H "Authorization: Bearer $KEY" $BASE/jobs/<jobId>

# 6. Download in any format
curl -s -H "Authorization: Bearer $KEY" "$BASE/documents/<jobId>?format=pdf"  -o policy.pdf
curl -s -H "Authorization: Bearer $KEY" "$BASE/documents/<jobId>?format=docx" -o policy.docx

# 7. Check my meter
curl -s -H "Authorization: Bearer $KEY" $BASE/usage

Billing & credits

Every live operation draws down a prepaid token balance — there is no subscription. Prices per operation and your current balance are always visible via GET /billing. Sandbox mode is free and does not touch your balance.

OperationTokens
Library ingest / refresh400,000 per document
Library search5,000 per query

Discovery, generation and mapping prices are listed in GET /billing and GET /capabilities.

Credit packTokens
pack10 — US$103.3M
pack25 — US$258.3M
pack50 — US$5016.7M
pack100 — US$10033.3M
pack200 — US$20070M (+5% bonus)
pack500 — US$500183.3M (+10% bonus)
# Buy credits — returns a secure Stripe payment URL to open in a browser
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"pack":"pack100"}' $BASE/billing/checkout
# → {"url":"https://…", "sessionId":"cs_…", "pack":{…}}
# Credits land on your balance automatically once payment completes.

Platform plan — running meter

Clients on the platform plan (a stateful compliance workspace — library, generated documents, saved artefacts) carry a small daily meter that keeps the workspace active: 222,222 tokens/day (≈US$20/month equivalent), with the first 1 GB of stored library included and 33,333 tokens/GB/day beyond that. This US$20/month meter does NOT apply to API-plan clients — the API plan has its own, much smaller meter (next section).

API plan — running meter

Clients on the API plan carry the same style of daily keep-alive meter, but at a tenth of the platform rate: 22,222 tokens/day (≈US$2/month equivalent), with the same first 1 GB of stored library included and 33,333 tokens/GB/day beyond that. To be clear: the US$20/month platform meter never applies to API clients — your only recurring cost is the ≈US$2/month-equivalent keep-alive, plus the tokens for the calls you make.

No cash transactions, ever. On both plans the meter is deducted from your prepaid token balance — there is no subscription, no card on file and no automatic cash charge. Check your plan and live meter details (daily rate, footprint, estimated days remaining) any time in GET /billing under meter — your integration can read meter.plan, meter.dailyFloorTokens and meter.monthlyUsdEquivalent programmatically.

If your balance reaches zero (either plan) the account becomes read-only — service pauses, but nothing is deleted, and reads, GET /billing and POST /billing/checkout always stay open, so you can top up at any moment to reactivate immediately. You have a 14-day grace period to top up; after that the workspace moves to 90-day retention and an archived export is offered before anything is removed. A low-balance email is sent when roughly a week of meter remains.

Two contacts, two lanes. Each client has a primary technical contact (onboarding, integration and review mail) and a billing / owner contact (top-up reminders, low-balance alerts and auto-top-up checkout links). Both are stated in your onboarding email; if no separate billing contact is on file, billing mail falls back to the technical contact. Reply to any of our emails to change either.

Larger volumes (US$1,000+) are arranged as invoiced credit blocks through your Kurateq account contact.

Auto-top-up (opt-in)

Never let a workspace drift into read-only: enable auto-top-up with a threshold and a pack choice, and when your balance dips below the threshold we email your billing / owner contact a prefilled Stripe checkout link for that pack — once per dip, never more. No card is ever stored with us; payment always completes on Stripe's own checkout page, and credits land automatically after payment.

PUT /api/public/v1/billing/auto-topup
{ "enabled": true, "thresholdTokens": 1000000, "pack": "pack50" }

Check the current setting with GET /billing/auto-topup (also mirrored in GET /billing). Disable any time with {"enabled": false}. The threshold minimum is 100,000 tokens — pick roughly a few days of your typical burn (1,000,000 ≈ 4 days of the platform meter floor).

Compliance calendar (opt-in)

Compliance is a rhythm, not a one-off. Set a review cadence and we email your technical contact a reminder each cycle with the standard review loop: refresh changed documents (POST /library/documents/{id}/refresh), re-run evidence mapping (POST /documents/map), pull framework updates (GET /frameworks/{slug}) and regenerate any drifted policies (POST /documents/generate).

PUT /api/public/v1/calendar
{ "cadence": "quarterly" }            // none | monthly | quarterly
// optional: "firstReviewAt": "2026-08-01T00:00:00Z"

The first reminder defaults to one cadence from now; check GET /calendar for the next scheduled date. Reminders are advice only — nothing runs or is charged automatically.

Rate limits & quotas

ControlBehaviour
Request ratePer-key requests-per-minute limit. Current allowance is returned in X-RateLimit-Limit / X-RateLimit-Remaining headers; exceeding it returns 429 with a retry hint.
Generation quotasPer-day and per-30-day caps on document generation, per key. Sandbox keys get generous multiples since sandbox costs nothing.
ConcurrencyOne generation job in flight per key. A second POST /documents/generate while one is running returns 409 job_already_running — poll the first job to completion.

Your exact numbers are always visible via GET /capabilities (limits) and GET /usage (consumption). Limit increases are arranged through your Kurateq account contact.

Errors

Every error — including malformed JSON bodies and unknown paths — returns a JSON envelope, never HTML:

{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests.",
    "hint": "Retry after 12s",
    "requestId": "req_..."
  }
}

Include the requestId in any support query — it lets us trace the exact request.

StatusMeaning
400Malformed JSON or invalid parameters (e.g. unsupported_format)
401Missing or invalid API key
404Unknown path or job (job_not_found)
409A generation job is already running for this key
429Rate limit exceeded — honour the retry hint
5xxOur side — retry with backoff; contact support with the requestId if it persists