Complete this flow with a test key to get a verdict and a checked proof. All examples use https://api.acretix.io and read ACRETIX_API_KEY from the environment.
Create a test tenant API key and put it in ACRETIX_API_KEY. A test key works for every step below; no production key is required.
A rubric is your success criteria. The examples compile a minimal invoice rule and retain its content hash.
Submit work with an Idempotency-Key. wait_ms holds the request open for up to 45 seconds; if it returns queued or running, poll the verification resource until it completes.
A completed verification has an append-only, Ed25519-signed proof envelope. Fetch it using the verification id.
For a relying-party verification rather than this convenience endpoint, follow the pinned trust root recipe in Verify a proof: independently resolve keys, anchor the server-served proof head, and bind the expected subject.
When you know whether a verdict was right, wrong or disputed, send it with POST /v1/verifications/{id}/feedback. It is counted in your project's own AI record. It never changes a verdict, an escalation or the engine's calibration. This is optional and not part of the quickstart flow.
POST the envelope from step 4 with expectedRubricHash set to the hash returned by step 2. A successful response has valid: true.
The curl version uses jq to retain response values.
export API=https://api.acretix.io
export KEY="$ACRETIX_API_KEY"
test -n "$KEY" || { echo 'Set ACRETIX_API_KEY first'; exit 1; }
# 2. Compile a rubric. Keep both values: the hash binds the proof check.
RUBRIC=$(curl -sS -X POST $API/v1/rubrics \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name":"quickstart-invoice","criteria":[{"key":"has_invoice","type":"must_have","primitive":"regex_match@1","config":{"pattern":"INV-[0-9]+"}}]}')
RUBRIC_ID=$(printf '%s' "$RUBRIC" | jq -r .rubric_id)
RUBRIC_HASH=$(printf '%s' "$RUBRIC" | jq -r .hash)
# 3. Verify a submission. Idempotency-Key makes a retry safe; wait_ms waits up to 45 seconds.
VERIFICATION=$(curl -sS -X POST $API/v1/verify \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-invoice-1" \
-d "{\"rubric_id\":\"$RUBRIC_ID\",\"submission\":{\"inline\":\"INV-4821 total \$1,250.50\"},\"options\":{\"wait_ms\":45000}}")
ID=$(printf '%s' "$VERIFICATION" | jq -r '.id // .verification_id')
STATUS=$(printf '%s' "$VERIFICATION" | jq -r .status)
while [ "$STATUS" = queued ] || [ "$STATUS" = running ]; do
sleep 1
VERIFICATION=$(curl -sS $API/v1/verifications/$ID -H "Authorization: Bearer $KEY")
STATUS=$(printf '%s' "$VERIFICATION" | jq -r .status)
done
printf '%s\n' "$VERIFICATION" # the completed verdict
# 4. Fetch the signed proof envelope returned for this completed verification.
curl -sS $API/v1/verifications/$ID/proof/envelope -H "Authorization: Bearer $KEY" > envelope.json
# 7. Check the proof envelope. The public endpoint returns { "valid": true } for this envelope and rubric hash.
jq --arg expectedRubricHash "$RUBRIC_HASH" '{ proof: ., expectedRubricHash: $expectedRubricHash }' envelope.json | \
curl -sS -X POST $API/v1/proofs/verify -H "Content-Type: application/json" --data-binary @-// Node 18+; fetch is built in. Set ACRETIX_API_KEY in your environment.
const API = 'https://api.acretix.io';
const key = process.env.ACRETIX_API_KEY;
if (!key) throw new Error('Set ACRETIX_API_KEY first');
async function api(path: string, init: RequestInit = {}) {
const response = await fetch(API + path, {
...init,
headers: { Authorization: 'Bearer ' + key, ...init.headers },
});
const body = await response.json();
if (!response.ok) throw new Error(JSON.stringify(body));
return body;
}
// 2. Compile a rubric; retain its hash for the proof check.
const rubric = await api('/v1/rubrics', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'quickstart-invoice', criteria: [
{ key: 'has_invoice', type: 'must_have', primitive: 'regex_match@1', config: { pattern: 'INV-[0-9]+' } },
] }),
});
// 3. Submit, then poll only when bounded sync returns queued/running.
let verification = await api('/v1/verify', {
method: 'POST', headers: { 'Content-Type': 'application/json', 'Idempotency-Key': 'quickstart-invoice-1' },
body: JSON.stringify({ rubric_id: rubric.rubric_id, submission: { inline: 'INV-4821 total $1,250.50' }, options: { wait_ms: 45000 } }),
});
const id = verification.id ?? verification.verification_id;
while (verification.status === 'queued' || verification.status === 'running') {
await new Promise((resolve) => setTimeout(resolve, 1000));
verification = await api(`/v1/verifications/${id}`);
}
console.log(verification); // the completed verdict
// 4. Fetch the signed proof envelope, then 7. check it against the compiled rubric hash.
const envelope = await api(`/v1/verifications/${id}/proof/envelope`);
const checked = await api('/v1/proofs/verify', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ proof: envelope, expectedRubricHash: rubric.hash }),
});
if (!checked.valid) throw new Error(checked.reason);
console.log(checked); // { valid: true, ... }# Python 3 standard library only. Set ACRETIX_API_KEY in your environment.
import json
import os
import time
import urllib.request
API = 'https://api.acretix.io'
KEY = os.environ['ACRETIX_API_KEY']
def api(path, method='GET', body=None, headers=None):
encoded = json.dumps(body).encode() if body is not None else None
request = urllib.request.Request(API + path, data=encoded, method=method)
request.add_header('Authorization', 'Bearer ' + KEY)
if body is not None:
request.add_header('Content-Type', 'application/json')
for name, value in (headers or {}).items():
request.add_header(name, value)
with urllib.request.urlopen(request) as response:
return json.load(response)
# 2. Compile a rubric; retain its hash for the proof check.
rubric = api('/v1/rubrics', 'POST', {
'name': 'quickstart-invoice',
'criteria': [{'key': 'has_invoice', 'type': 'must_have', 'primitive': 'regex_match@1',
'config': {'pattern': 'INV-[0-9]+'}}],
})
# 3. Submit with an Idempotency-Key and wait_ms, polling only if needed.
verification = api('/v1/verify', 'POST', {
'rubric_id': rubric['rubric_id'],
'submission': {'inline': 'INV-4821 total $1,250.50'},
'options': {'wait_ms': 45000},
}, {'Idempotency-Key': 'quickstart-invoice-1'})
verification_id = verification.get('id', verification.get('verification_id'))
while verification['status'] in ('queued', 'running'):
time.sleep(1)
verification = api(f'/v1/verifications/{verification_id}')
print(verification) # the completed verdict
# 4. Fetch the signed proof envelope, then 7. check it against the compiled rubric hash.
envelope = api(f'/v1/verifications/{verification_id}/proof/envelope')
checked = api('/v1/proofs/verify', 'POST', {
'proof': envelope,
'expectedRubricHash': rubric['hash'],
})
if not checked['valid']:
raise RuntimeError(checked['reason'])
print(checked) # { 'valid': True, ... }