Quickstart
Set a spend cap. Submit a run. Inspect the receipt.
The Decisionproof API turns AI runs into budget-bounded, auditable, settlement-safe operations. Every run reserves a spend cap upfront, captures a result artifact on success, and settles cost only against that receipt. The snippets below assume an active paid private beta subscription.
Prerequisites
- An active paid private beta subscription (see pricing)
- An API key — create one from your dashboard (format:
dp_live_{secret}; up to 3 keys per workspace during beta) - Any HTTP client: curl, Python requests, Node.js fetch, etc.
Base URL
https://api.decisionproof.io.kr
Authentication
All requests require an API key in the Authorization header:
Authorization: Bearer dp_live_your_key_here
Submit a run
The API is asynchronous:
- POST to
/v1/runs— receive202 Acceptedwith arun_id - Poll
/v1/runs/{run_id}untilstatusiscompletedorfailed - Download the result from
presigned_url
cURL
curl -X POST https://api.decisionproof.io.kr/v1/runs \
-H "Authorization: Bearer dp_live_your_key_here" \
-H "Idempotency-Key: my-unique-key-123" \
-H "Content-Type: application/json" \
-d '{
"pack_type": "decision",
"inputs": {
"question": "Should we proceed with Plan A?",
"context": "Budget 50000 USD, timeline Q2"
},
"reservation": {
"max_cost_usd": "0.0500"
}
}'
Python
import requests, time
response = requests.post(
"https://api.decisionproof.io.kr/v1/runs",
headers={
"Authorization": "Bearer dp_live_your_key_here",
"Idempotency-Key": "my-unique-key-123",
"Content-Type": "application/json"
},
json={
"pack_type": "decision",
"inputs": {
"question": "Should we proceed with Plan A?",
"context": "Budget 50000 USD, timeline Q2"
},
"reservation": {
"max_cost_usd": "0.0500"
}
}
)
assert response.status_code == 202
receipt = response.json()
run_id = receipt["run_id"]
poll_url = f"https://api.decisionproof.io.kr{receipt['poll']['href']}"
Node.js
const response = await fetch("https://api.decisionproof.io.kr/v1/runs", {
method: "POST",
headers: {
"Authorization": "Bearer dp_live_your_key_here",
"Idempotency-Key": "my-unique-key-123",
"Content-Type": "application/json"
},
body: JSON.stringify({
pack_type: "decision",
inputs: { question: "Should we proceed with Plan A?" },
reservation: { max_cost_usd: "0.0500" }
})
});
if (response.status !== 202) throw new Error(`Expected 202, got ${response.status}`);
const receipt = await response.json();
const runId = receipt.run_id;
Response (202 Accepted):
{
"run_id": "5f2c1e58-6b3a-4f19-9c5d-8e4a2b7d0c31",
"status": "queued",
"poll": {
"href": "/v1/runs/5f2c1e58-6b3a-4f19-9c5d-8e4a2b7d0c31",
"recommended_interval_ms": 1500,
"max_wait_sec": 90
},
"reservation": {
"max_cost_usd": "0.0500",
"currency": "USD"
},
"meta": {
"created_at": "2026-07-10T09:00:00+00:00",
"trace_id": "",
"profile_version": "v0.4.2.2"
}
}
reservation.max_cost_usd is the per-run spend cap —
the maximum USD amount reserved for a single run. It is not a
monthly, account-level, or workspace-level budget. The per-run
spend cap during the Sandbox paid private beta is US$5.00.
Reserve what you expect; you'll be charged only the settled cost
once the result artifact and its receipt metadata are captured.
Poll for status
Poll until status is completed or failed:
Python polling loop
while True:
time.sleep(1.5)
r = requests.get(poll_url, headers={"Authorization": "Bearer dp_live_your_key_here"})
run = r.json()
if run["status"] in ("completed", "failed"):
break
if run["status"] == "completed":
print("Result URL:", run["result"]["presigned_url"])
Get results
When status is completed, the response includes
result.presigned_url — a short-lived S3 URL. Download it directly:
curl -o result.json "https://s3.amazonaws.com/..."
Error handling
All errors follow RFC 9457 Problem Details:
{
"type": "https://api.decisionproof.io.kr/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid or expired API key."
}
Key status codes:
401— invalid or expired API key402— entitlement inactive (subscription expired or not active)422— invalid request body429— rate limit exceeded (Retry-Afterheader included)
When Decisionproof refuses: stop, do not fall through
A 429 (quota-exceeded) or a 402 (entitlement inactive, or insufficient execution budget) means Decisionproof has refused the run and has recorded the refusal. Each refusal is stored with its type, the time it first occurred, the time it last occurred and the number of requests refused, and it is retrievable through GET /v1/tenants/{tenant_id}/usage.
The recommended handling is fail-closed: halt the agent and surface the refusal. Decisionproof records the executions it governs and the refusals it issues; it cannot record what your systems do outside it. An integration that falls through to a model provider directly on a refusal produces executions that exist in your logs and in no Decisionproof record, and no later reconciliation can recover them from this side.
If a fail-open path is unavoidable, log the reason code, the time and the request identity on your side so the two records can be reconciled afterwards.
To restore capacity before the cycle ends, renew early or move to a higher tier. Either starts a new cycle, resets the metered-operation counter, and preserves the days you have already paid for.