Agents and integrations
Connect, referrals and your own endpoint.
Give each of your users a sub-key and balance, earn a markup in USDF, and serve models through the gateway.
On this page
An account becomes a platform with a platform key. The platform key never spends: it mints one sub-key per end user and reads the platform's figures. On the dashboard: Connect.
1. Create the platform key
Under your session. It is shown once, and it cannot call chat. Samples read it from $PLATFORM_KEY.
Create a platform key
curl -X POST https://api.usdf.fi/v1/platform/create \ -H "Authorization: Bearer $SESSION"
Response
{
"key_id": "<key_id>",
"api_key": "sk_…",
"key_prefix": "<prefix>",
"role": "platform",
"note": "Shown once. This key mints sub-keys … it cannot call /v1/chat/completions itself."
}2. Set your markup
markup_bps is 0 to 5000 basis points of the sheet cost. It is credited to your balance as each request is billed.
Set the markup
curl -X PATCH https://api.usdf.fi/v1/platform \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{"markup_bps": 250}'3. Know the limit
Platform calls are limited to — per platform key. A sub-key is an ordinary API key, with the per-key limit: —.
A sub-key is an ordinary API key with its own balance, funded from the end user's own wallet. A wallet is bound to a sub-key only by the wallet's own signature.
1. Ask for the wallet proof
Wallet proof
curl -X POST https://api.usdf.fi/v1/platform/wallet-proof \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{"end_user_ref": "user-a", "wallet_address": "<end user wallet>"}'Response
{
"end_user_ref": "user-a",
"wallet_address": "<end user wallet>",
"nonce": "<nonce>",
"message": "<message the end user signs>",
"sign": "personal_sign (EIP-191) by wallet_address"
}2. The end user signs
The end user's wallet signs message with personal_sign. The nonce is single use.
3. Mint the sub-key
Mint a sub-key
curl -X POST https://api.usdf.fi/v1/platform/keys \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"end_user_ref": "user-a",
"limits": {
"budget_units": "10000000",
"rate_limit_rpm": 60,
"spend_limit_hour_units": "1000000",
"spend_limit_day_units": "5000000"
},
"wallet_address": "<end user wallet>",
"wallet_nonce": "<nonce>",
"wallet_signature": "<signature>"
}'Response
{
"key_id": "<sub_key_id>",
"api_key": "sk_…",
"key_prefix": "<prefix>",
"end_user_ref": "user-a",
"role": "sub",
"wallet_address": "<end user wallet>",
…
}The fields:
| Field | Rules |
|---|---|
end_user_ref | Your own id for the end user, 1 to 128 characters. |
limits | budget_units, rate_limit_rpm, spend_limit_hour_units, spend_limit_day_units. |
wallet_address, wallet_nonce, wallet_signature | Optional. With a wallet, the proof is required, and deposits from that wallet credit the sub-key. |
Manage sub-keys with the platform key:
| Endpoint | What it does |
|---|---|
GET /v1/platform/keys | Every sub-key: balance, held, spent, limits, pause state. |
POST /v1/platform/keys/{id}/wallet | Sets the sub-key's wallet, with a new proof. |
POST /v1/platform/keys/{id}/withdraw | Returns unspent balance to the sub-key's own wallet: amount_units, at least 0.10 USDF. |
POST /v1/platform/keys/{id}/revoke | Revokes it, once its balance is zero. |
Return a sub-key's balance
curl -X POST https://api.usdf.fi/v1/platform/keys/<sub_key_id>/withdraw \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{"amount_units": "1000000"}'A sub-key's withdrawals: at most 3 open and 10 per day. Its holds include the markup, so 402 insufficient_balance means the balance cannot cover cost plus markup.
GET /v1/platform/usage reports requests, tokens, cost and markup per end user, with days and end_user_ref. /v1/platform/usage.csv is the same as CSV.
Read usage
curl "https://api.usdf.fi/v1/platform/usage?days=30&end_user_ref=user-a" \ -H "Authorization: Bearer $PLATFORM_KEY"
Your markup earnings are paid in USDF to your account balance, and withdraw like any balance. See Withdraw.
The buy embed lets an end user fund their sub-key from their own wallet, inside your product. Frame /embed/buy?key=<sub_key_id>; it reads GET /v1/platform/embed/{sub_key_id}, which is public. See the embed.
Show that you accept USDF with the badge:
Badge HTML
<a href="https://api.usdf.fi/v1/pricing"> <img src="https://api.usdf.fi/badge.svg" alt="Accepts USDF"> </a>
See Connect for the overview.
Loading…
| Endpoint | What it does |
|---|---|
GET /v1/referrals | Your code, link and earnings. Session, or the account's own API key. |
POST /v1/referrals/attach | Attaches a referral code to your account. Session. |
GET /v1/referrals/terms | The terms above, read live. Public. |
Your link is on the dashboard, under Referrals. See Affiliates.
Register an OpenAI-compatible chat completions endpoint, and the gateway routes requests to it beside its other routes. You are credited the upstream cost of every request you serve, at your own price, in USDF.
Your route serves requests paid from a user account's own balance. Requests made with a team key, a platform sub-key or an agent key run on the other routes.
1. Register
POST /v1/providers, under your session. The account needs a linked wallet: earnings are withdrawn to it.
Register an endpoint
curl -X POST https://api.usdf.fi/v1/providers \
-H "Authorization: Bearer $SESSION" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Compute",
"slug": "acme",
"base_url": "https://api.example.com/v1",
"auth": { "header": "authorization", "value": "Bearer sk-..." },
"data_policy": { "retains": false, "trains": false, "region": "us" },
"models": [
{
"id": "llama-3.3-70b-instruct",
"upstream_model": "acme/llama-70b",
"input_price": 0.08, "output_price": 0.2,
"context": 65536, "max_output": 8192
},
{
"id": "sp-acme.house-7b", "name": "House 7B",
"upstream_model": "house-7b",
"input_price": 0.2, "output_price": 0.6,
"context": 32768, "max_output": 4096
}
]
}'Response, 201, trimmed
{
"provider": {
"id": "sp-acme",
"status": "pending",
"proof": { "url": "https://api.example.com/.well-known/usdf-provider.txt", "token": "sp-acme:…" },
"models": [ { "id": "llama-3.3-70b-instruct", "status": "unverified", "serving": false, … }, … ],
…
},
"next": "Serve this token as a line of … then POST /v1/providers/sp-acme/verify: …"
}The fields:
| Field | Rules |
|---|---|
name | Your endpoint's name. |
slug | 3 to 24 lower-case letters, digits or hyphens; from name when left out. The endpoint's id is sp-<slug>, the provider name on routes, usage rows and receipts. |
base_url | https:// on port 443 and a public DNS name that resolves to public addresses only. The gateway calls <base_url>/chat/completions. |
auth | The one header the gateway sends with every request: authorization (the default), api-key or an x- header of your own. The value is sealed before it is stored, and no endpoint returns it. |
data_policy | retains and trains (booleans) and an optional region. A declaration, shown as one on receipts. |
models | Each with id (a catalog model, or a new one named sp-<slug>.<name>), upstream_model, input_price and output_price in USD per 1M tokens, context and max_output. |
For a catalog model, your price must be at least 5% below the cheapest route the price sheet lists for it, in every rate it bills. Otherwise the registration is refused with 400 priced_above_sheet. Callers keep paying the sheet's price. A new model of your own gets a sheet entry at your price plus the published markup.
2. Prove control of the origin
Serve provider.proof.token from the answer as a line of its own, answering 200 itself, with no redirect:
Proof file
https://api.example.com/.well-known/usdf-provider.txt <provider.proof.token, on a line of its own>
3. Ask for the check
Once the file is in place, ask the gateway to read it. It then sends each model one real streamed request; a model serves once its check passes.
Verify the endpoint
curl -X POST https://api.usdf.fi/v1/providers/sp-acme/verify \ -H "Authorization: Bearer $SESSION"
Response, 202, trimmed
{
"provider": { "id": "sp-acme", "status": "active", … },
"proof": { "ok": true, "error": null },
"checks": "started",
"next": "…"
}4. Serve and earn
| Endpoint | What it does |
|---|---|
GET /v1/providers/me | Your endpoints, each route's check status, and your earnings. |
POST /v1/providers/me/withdraw | Withdraws the balance to the linked wallet, as USDF: {"units": "…"}. |
DELETE /v1/providers/{id} | Stops the endpoint's routes. Recorded earnings stay. |
GET /v1/providers | The public list of active providers with a verified route. |
An earning is credited once it is a day old. A catalog model's route takes the model's default traffic once it is approved. Until then it serves requests that name it with provider.only. Refusals are on Errors.