curl --request POST \
--url https://api.kordio.io/control/v1/agent/payment_intents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 12000,
"idempotency_key": "order-4471-attempt-1",
"counterparty": "acme-supplies.example",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trace_id": "<string>",
"decision_context": {},
"metadata": {}
}
'import requests
url = "https://api.kordio.io/control/v1/agent/payment_intents"
payload = {
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 12000,
"idempotency_key": "order-4471-attempt-1",
"counterparty": "acme-supplies.example",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trace_id": "<string>",
"decision_context": {},
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
budget_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
amount_cents: 12000,
idempotency_key: 'order-4471-attempt-1',
counterparty: 'acme-supplies.example',
spend_token_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
trace_id: '<string>',
decision_context: {},
metadata: {}
})
};
fetch('https://api.kordio.io/control/v1/agent/payment_intents', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kordio.io/control/v1/agent/payment_intents",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'budget_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'amount_cents' => 12000,
'idempotency_key' => 'order-4471-attempt-1',
'counterparty' => 'acme-supplies.example',
'spend_token_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'trace_id' => '<string>',
'decision_context' => [
],
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kordio.io/control/v1/agent/payment_intents"
payload := strings.NewReader("{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kordio.io/control/v1/agent/payment_intents")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kordio.io/control/v1/agent/payment_intents")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "4a7c2e18-9b05-4f63-8d21-6e0a3c7f5b94",
"workspace_id": "1c4f8b20-9e77-4a31-b5d2-06a8c3e91f4d",
"agent_id": "7d2a6c15-3f89-4b02-9e64-8a15d7c0b3f2",
"budget_id": "3f1c8a92-5d41-4c8e-9f2b-7a6e1d0c4b83",
"spend_token_id": null,
"amount_cents": 12000,
"currency": "USD",
"counterparty": "acme-supplies.example",
"state": "pending",
"failure_reason": null,
"idempotency_key": "order-4471-attempt-1",
"created_at": "2026-08-04T09:12:04Z"
},
"decision": {
"outcome": "allowed",
"rule": null,
"detail": {},
"headroom": {
"session_remaining_cents": 38000
},
"policy_snapshot": [],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": null
},
"cosignature": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImtleV8xIiwidHlwIjoiSldUIn0"
}{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 123,
"currency": "<string>",
"counterparty": "<string>",
"state": "pending",
"failure_reason": "<string>",
"resolved_by_sub": "<string>",
"resolved_at": "2023-11-07T05:31:56Z",
"idempotency_key": "<string>",
"trace_id": "<string>",
"ledger_transaction_id": "<string>",
"decision_context": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"decision": {
"outcome": "allowed",
"rule": "per_transaction_cap",
"detail": {},
"headroom": {},
"policy_snapshot": [
{}
],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": {
"kind": "lower_amount",
"summary": "A per-action cap applies. Retry at $100.00 or less.",
"max_cents": 123,
"retry_after_seconds": 123,
"resource": "<string>",
"action_type": "<string>"
}
},
"cosignature": "<string>"
}{
"error": {
"message": "<string>",
"code": "runtime_key_required"
}
}{
"error": {
"message": "Agent key is required",
"code": "runtime_key_required"
}
}{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 123,
"currency": "<string>",
"counterparty": "<string>",
"state": "pending",
"failure_reason": "<string>",
"resolved_by_sub": "<string>",
"resolved_at": "2023-11-07T05:31:56Z",
"idempotency_key": "<string>",
"trace_id": "<string>",
"ledger_transaction_id": "<string>",
"decision_context": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"decision": {
"outcome": "allowed",
"rule": "per_transaction_cap",
"detail": {},
"headroom": {},
"policy_snapshot": [
{}
],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": {
"kind": "lower_amount",
"summary": "A per-action cap applies. Retry at $100.00 or less.",
"max_cents": 123,
"retry_after_seconds": 123,
"resource": "<string>",
"action_type": "<string>"
}
},
"cosignature": "<string>"
}{
"error": {
"message": "<string>",
"code": "runtime_key_required"
}
}Authorize a payment
Evaluated as the action type payment.create with the counterparty as its
resource, so an agent’s caps, windows and allowlists apply across payments and
other actions together. Spend on one consumes headroom for the other.
One difference from POST /v1/agent/actions that will bite you if you assume
symmetry:
- Idempotency is a body field here,
idempotency_key, not theIdempotency-Keyheader. A missing one is a400, not a422.
Kordio authorizes the payment; it never moves the money. An allowed payment comes
back pending with a cosignature. Settle it on your own rail, then report the
outcome with complete or fail.
curl --request POST \
--url https://api.kordio.io/control/v1/agent/payment_intents \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 12000,
"idempotency_key": "order-4471-attempt-1",
"counterparty": "acme-supplies.example",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trace_id": "<string>",
"decision_context": {},
"metadata": {}
}
'import requests
url = "https://api.kordio.io/control/v1/agent/payment_intents"
payload = {
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 12000,
"idempotency_key": "order-4471-attempt-1",
"counterparty": "acme-supplies.example",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trace_id": "<string>",
"decision_context": {},
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
budget_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
amount_cents: 12000,
idempotency_key: 'order-4471-attempt-1',
counterparty: 'acme-supplies.example',
spend_token_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
trace_id: '<string>',
decision_context: {},
metadata: {}
})
};
fetch('https://api.kordio.io/control/v1/agent/payment_intents', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kordio.io/control/v1/agent/payment_intents",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'budget_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'amount_cents' => 12000,
'idempotency_key' => 'order-4471-attempt-1',
'counterparty' => 'acme-supplies.example',
'spend_token_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'trace_id' => '<string>',
'decision_context' => [
],
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kordio.io/control/v1/agent/payment_intents"
payload := strings.NewReader("{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kordio.io/control/v1/agent/payment_intents")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kordio.io/control/v1/agent/payment_intents")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budget_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount_cents\": 12000,\n \"idempotency_key\": \"order-4471-attempt-1\",\n \"counterparty\": \"acme-supplies.example\",\n \"spend_token_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"trace_id\": \"<string>\",\n \"decision_context\": {},\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "4a7c2e18-9b05-4f63-8d21-6e0a3c7f5b94",
"workspace_id": "1c4f8b20-9e77-4a31-b5d2-06a8c3e91f4d",
"agent_id": "7d2a6c15-3f89-4b02-9e64-8a15d7c0b3f2",
"budget_id": "3f1c8a92-5d41-4c8e-9f2b-7a6e1d0c4b83",
"spend_token_id": null,
"amount_cents": 12000,
"currency": "USD",
"counterparty": "acme-supplies.example",
"state": "pending",
"failure_reason": null,
"idempotency_key": "order-4471-attempt-1",
"created_at": "2026-08-04T09:12:04Z"
},
"decision": {
"outcome": "allowed",
"rule": null,
"detail": {},
"headroom": {
"session_remaining_cents": 38000
},
"policy_snapshot": [],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": null
},
"cosignature": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImtleV8xIiwidHlwIjoiSldUIn0"
}{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 123,
"currency": "<string>",
"counterparty": "<string>",
"state": "pending",
"failure_reason": "<string>",
"resolved_by_sub": "<string>",
"resolved_at": "2023-11-07T05:31:56Z",
"idempotency_key": "<string>",
"trace_id": "<string>",
"ledger_transaction_id": "<string>",
"decision_context": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"decision": {
"outcome": "allowed",
"rule": "per_transaction_cap",
"detail": {},
"headroom": {},
"policy_snapshot": [
{}
],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": {
"kind": "lower_amount",
"summary": "A per-action cap applies. Retry at $100.00 or less.",
"max_cents": 123,
"retry_after_seconds": 123,
"resource": "<string>",
"action_type": "<string>"
}
},
"cosignature": "<string>"
}{
"error": {
"message": "<string>",
"code": "runtime_key_required"
}
}{
"error": {
"message": "Agent key is required",
"code": "runtime_key_required"
}
}{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"budget_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"spend_token_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount_cents": 123,
"currency": "<string>",
"counterparty": "<string>",
"state": "pending",
"failure_reason": "<string>",
"resolved_by_sub": "<string>",
"resolved_at": "2023-11-07T05:31:56Z",
"idempotency_key": "<string>",
"trace_id": "<string>",
"ledger_transaction_id": "<string>",
"decision_context": {},
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"decision": {
"outcome": "allowed",
"rule": "per_transaction_cap",
"detail": {},
"headroom": {},
"policy_snapshot": [
{}
],
"policy_version": "pv_8f2c1d0a4b6e93571ac2e8d045f7b312",
"frame_hash": "fh_1b9a0c7e5d2f483610badc0ffee1234567890abcdef1234567890abcdef123456",
"remedy": {
"kind": "lower_amount",
"summary": "A per-action cap applies. Retry at $100.00 or less.",
"max_cents": 123,
"retry_after_seconds": 123,
"resource": "<string>",
"action_type": "<string>"
}
},
"cosignature": "<string>"
}{
"error": {
"message": "<string>",
"code": "runtime_key_required"
}
}Authorizations
An agent API key, krt_live_... or krt_test_..., shown exactly once at creation. Kordio stores only a digest. This credential can ask for authorization and can never write policy.
Body
x >= 112000
Required, and sent in the body rather than as a header. Unique per agent. A replay returns the original intent and decision at the original status.
"order-4471-attempt-1"
"acme-supplies.example"
A token minted by this agent against the same session.
Free-form context stored with the intent and echoed back, with the decision merged in under the key decision. Provenance only: policy never reads it. Put anything a rule must evaluate in metadata.
Facts the policy engine evaluates, reachable in a rule as metadata.<key> with dot paths for nested values. Same field, same meaning, as on POST /v1/agent/actions.