Keys and accounts
Child keys and moving funds
A root key (or a passkey account) mints child keys: ordinary gk_ keys with their own balance. Money moves between root and children by transfer, so the total never changes.
Rules
- Every
gk_key without a parent is a root. A child cannot create children. - A root holds at most 100 live children and may create 30 per hour.
- Funding moves money from the root to the child; reclaiming moves the child's available balance (funded minus spent minus held by requests in flight) back. Money held by a request in flight never moves.
- The root is the account: a child stops working when its root is deleted, disabled or suspended.
- Children of one root are linkable to each other. Use separate roots when keys must stay unlinkable.
Endpoints
All need Authorization: Bearer <root key> or a passkey session; a child key gets 403 forbidden. Amounts are amount_usd in whole cents (400 invalid_amount otherwise); more than is available is 402 insufficient_funds; an unknown child id is 404 key_not_found.
| Request | Result |
|---|---|
POST /v1/keys/children {name?, amount_usd?, expires_at?} | 201 {key, data, root}; key is shown once. expires_at is ISO 8601 or epoch milliseconds. |
GET /v1/keys/children | The live children with balances, never secrets. |
POST /v1/keys/children/:id/fund {amount_usd} | {data, root, transferred_micros}; 409 key_expired for an expired child. |
POST /v1/keys/children/:id/reclaim {amount_usd} or {all: true} | Same shape. |
DELETE /v1/keys/children/:id | {deleted: true, reclaimed_micros, root}; repeating it reclaims 0. |
Transfers are limited to 600 per hour per root.
Example
# Mint a child with $5 that expires in a day
curl https://inference.dagon.so/v1/keys/children \
-H "Authorization: Bearer $DAGON_ROOT_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "ci runner", "amount_usd": 5, "expires_at": "2030-01-01T00:00:00Z"}'
# Take back whatever it has not spent
curl https://inference.dagon.so/v1/keys/children/$CHILD_ID/reclaim \
-H "Authorization: Bearer $DAGON_ROOT_KEY" \
-H "Content-Type: application/json" \
-d '{"all": true}'import os, requests
H = {"Authorization": f"Bearer {os.environ['DAGON_ROOT_KEY']}"}
child = requests.post("https://inference.dagon.so/v1/keys/children", headers=H,
json={"name": "ci runner", "amount_usd": 5}).json()
print(child["key"]) # shown once
requests.post(f"https://inference.dagon.so/v1/keys/children/{child['data']['id']}/reclaim", headers=H, json={"all": True})const H = { authorization: `Bearer ${process.env.DAGON_ROOT_KEY}`, "content-type": "application/json" };
const child = await (await fetch("https://inference.dagon.so/v1/keys/children", {
method: "POST", headers: H, body: JSON.stringify({ name: "ci runner", amount_usd: 5 }),
})).json();
console.log(child.key); // shown once
await fetch(`https://inference.dagon.so/v1/keys/children/${child.data.id}/reclaim`, { method: "POST", headers: H, body: JSON.stringify({ all: true }) });Last updated