Compose Keys
curl --request POST \
--url https://api.compose.market/api/keys \
--header 'Content-Type: application/json' \
--header 'x-session-user-address: <x-session-user-address>' \
--data '
{
"budgetLimit": {},
"expiresAt": {},
"chainId": {},
"purpose": "<string>",
"name": "<string>"
}
'import requests
url = "https://api.compose.market/api/keys"
payload = {
"budgetLimit": {},
"expiresAt": {},
"chainId": {},
"purpose": "<string>",
"name": "<string>"
}
headers = {
"x-session-user-address": "<x-session-user-address>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-session-user-address': '<x-session-user-address>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
budgetLimit: {},
expiresAt: {},
chainId: {},
purpose: '<string>',
name: '<string>'
})
};
fetch('https://api.compose.market/api/keys', 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.compose.market/api/keys",
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([
'budgetLimit' => [
],
'expiresAt' => [
],
'chainId' => [
],
'purpose' => '<string>',
'name' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-session-user-address: <x-session-user-address>"
],
]);
$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.compose.market/api/keys"
payload := strings.NewReader("{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-session-user-address", "<x-session-user-address>")
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.compose.market/api/keys")
.header("x-session-user-address", "<x-session-user-address>")
.header("Content-Type", "application/json")
.body("{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.compose.market/api/keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-session-user-address"] = '<x-session-user-address>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"keyId": "<string>",
"token": "<string>",
"budgetLimit": {},
"budgetRemaining": {}
}Payments & x402
Compose Keys
Create, list, inspect, settle, and revoke Compose Keys.
POST
/
api
/
keys
Compose Keys
curl --request POST \
--url https://api.compose.market/api/keys \
--header 'Content-Type: application/json' \
--header 'x-session-user-address: <x-session-user-address>' \
--data '
{
"budgetLimit": {},
"expiresAt": {},
"chainId": {},
"purpose": "<string>",
"name": "<string>"
}
'import requests
url = "https://api.compose.market/api/keys"
payload = {
"budgetLimit": {},
"expiresAt": {},
"chainId": {},
"purpose": "<string>",
"name": "<string>"
}
headers = {
"x-session-user-address": "<x-session-user-address>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-session-user-address': '<x-session-user-address>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
budgetLimit: {},
expiresAt: {},
chainId: {},
purpose: '<string>',
name: '<string>'
})
};
fetch('https://api.compose.market/api/keys', 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.compose.market/api/keys",
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([
'budgetLimit' => [
],
'expiresAt' => [
],
'chainId' => [
],
'purpose' => '<string>',
'name' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-session-user-address: <x-session-user-address>"
],
]);
$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.compose.market/api/keys"
payload := strings.NewReader("{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-session-user-address", "<x-session-user-address>")
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.compose.market/api/keys")
.header("x-session-user-address", "<x-session-user-address>")
.header("Content-Type", "application/json")
.body("{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.compose.market/api/keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-session-user-address"] = '<x-session-user-address>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"budgetLimit\": {},\n \"expiresAt\": {},\n \"chainId\": {},\n \"purpose\": \"<string>\",\n \"name\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"keyId": "<string>",
"token": "<string>",
"budgetLimit": {},
"budgetRemaining": {}
}Compose Keys are bearer credentials with a budget, expiry, purpose, owner wallet, and chain ID. They are used by native routes, paid runtime routes, and external OpenAI-compatible routes.
Routes
| Method | Path | Description |
|---|---|---|
POST | /api/keys | Create a Compose Key. |
GET | /api/keys | List keys owned by a wallet. |
GET | /api/keys/{keyId} | Inspect one key. |
DELETE | /api/keys/{keyId} | Revoke one key. |
POST | /api/keys/settle | Legacy direct settlement using a Compose Key. |
Create body
number | string
required
Positive integer budget in USDC atomic units.
number | string
required
Unix timestamp in milliseconds. Must be in the future.
number | string
required
Chain ID used for key settlement.
string
required
session or api.string
Optional display name.
Headers
string
required
Owner wallet address for create and list operations.
string
Required for inspecting and revoking a key:
Bearer compose-... for the target key or another live key owned by the same wallet.Response
string
Key identifier.
string
Bearer token returned when a key is created. List and inspect routes do not return token material.
string | number
Configured budget in USDC atomic units.
string | number
Available budget after used and reserved amounts.
⌘I