veltor
Developer documentation

REST examples

All server integrations use bearer keys and JSON. Keep server keys out of browsers, email links, and logs.

curl

Set VELTOR_SECRET_KEY in your shell’s secret environment. Replace example benefit and recipient values with your application’s identifiers.

curl https://veltor.tech/v1/decisions \
  -H "Authorization: Bearer $VELTOR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: attempt_customer_123" \
  --data '{
  "benefit": "signup_credits",
  "claim_id": "signup_customer_123",
  "subject": {"external_id": "customer_123", "email": "alex@example.com"},
  "context": {"ip": "192.0.2.1"}
}'

Python

Persist claim_id and the attempt key before sending. A timeout requires recovery with the same key, not another delivery attempt.

import os, requests
response = requests.post(
    "https://veltor.tech/v1/decisions",
    headers={"Authorization": "Bearer " + os.environ["VELTOR_SECRET_KEY"],
             "Idempotency-Key": "attempt_customer_123"},
    json={
  "benefit": "signup_credits",
  "claim_id": "signup_customer_123",
  "subject": {"external_id": "customer_123", "email": "alex@example.com"},
  "context": {"ip": "192.0.2.1"}
}, timeout=0.6
)
response.raise_for_status()
decision = response.json()
# Enforce allow/deny and deduplicate the actual grant.

PHP

Handle transport errors and HTTP errors separately from a successful decision. Do not log your key.

$request = curl_init('https://veltor.tech/v1/decisions');
curl_setopt_array($request, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT_MS => 600,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . getenv('VELTOR_SECRET_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: attempt_customer_123'
  ],
  CURLOPT_POSTFIELDS => '{
  "benefit": "signup_credits",
  "claim_id": "signup_customer_123",
  "subject": {"external_id": "customer_123", "email": "alex@example.com"},
  "context": {"ip": "192.0.2.1"}
}'
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
if ($body === false || $status !== 200) {
  throw new RuntimeException('Decision unavailable; reconcile this claim.');
}
$decision = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

Versioned API contract

Download the OpenAPI contract for supported fields, response codes, and request limits. Unsupported fields are rejected.