curl --request POST \
--url https://api.sandbox.nevermined.app/api/v1/x402/permissions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"resource": {
"url": "https://myagent.ai/api/v1/tasks",
"description": "AI agent task execution"
},
"accepted": {
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "44742763076047497640080230236781474129970992727896593861997347135613135571071",
"extra": {
"agentId": "80918427023170428029540261117198154464497879145267720259488529685089104529015",
"httpVerb": "POST"
}
},
"delegationConfig": {
"delegationId": "a1b2c3d4-e5f6-4a90-8bcd-ef1234567890"
}
}
'import requests
url = "https://api.sandbox.nevermined.app/api/v1/x402/permissions"
payload = {
"resource": {
"url": "https://myagent.ai/api/v1/tasks",
"description": "AI agent task execution"
},
"accepted": {
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "44742763076047497640080230236781474129970992727896593861997347135613135571071",
"extra": {
"agentId": "80918427023170428029540261117198154464497879145267720259488529685089104529015",
"httpVerb": "POST"
}
},
"delegationConfig": { "delegationId": "a1b2c3d4-e5f6-4a90-8bcd-ef1234567890" }
}
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({
resource: {url: 'https://myagent.ai/api/v1/tasks', description: 'AI agent task execution'},
accepted: {
scheme: 'nvm:erc4337',
network: 'eip155:84532',
planId: '44742763076047497640080230236781474129970992727896593861997347135613135571071',
extra: {
agentId: '80918427023170428029540261117198154464497879145267720259488529685089104529015',
httpVerb: 'POST'
}
},
delegationConfig: {delegationId: 'a1b2c3d4-e5f6-4a90-8bcd-ef1234567890'}
})
};
fetch('https://api.sandbox.nevermined.app/api/v1/x402/permissions', 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.sandbox.nevermined.app/api/v1/x402/permissions",
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([
'resource' => [
'url' => 'https://myagent.ai/api/v1/tasks',
'description' => 'AI agent task execution'
],
'accepted' => [
'scheme' => 'nvm:erc4337',
'network' => 'eip155:84532',
'planId' => '44742763076047497640080230236781474129970992727896593861997347135613135571071',
'extra' => [
'agentId' => '80918427023170428029540261117198154464497879145267720259488529685089104529015',
'httpVerb' => 'POST'
]
],
'delegationConfig' => [
'delegationId' => 'a1b2c3d4-e5f6-4a90-8bcd-ef1234567890'
]
]),
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.sandbox.nevermined.app/api/v1/x402/permissions"
payload := strings.NewReader("{\n \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\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.sandbox.nevermined.app/api/v1/x402/permissions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.nevermined.app/api/v1/x402/permissions")
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 \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\n}"
response = http.request(request)
puts response.read_body{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGFuSWQiOiI0MzI5ODQzMjk4NDMyOSIsImFnZW50SWQiOiIxMjM0NTY3ODkwMTIzNDU2Nzg5MCJ9.x402_signature_hash"
}Create Permission
Creates a delegated permission and generates an x402 access token.
curl --request POST \
--url https://api.sandbox.nevermined.app/api/v1/x402/permissions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"resource": {
"url": "https://myagent.ai/api/v1/tasks",
"description": "AI agent task execution"
},
"accepted": {
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "44742763076047497640080230236781474129970992727896593861997347135613135571071",
"extra": {
"agentId": "80918427023170428029540261117198154464497879145267720259488529685089104529015",
"httpVerb": "POST"
}
},
"delegationConfig": {
"delegationId": "a1b2c3d4-e5f6-4a90-8bcd-ef1234567890"
}
}
'import requests
url = "https://api.sandbox.nevermined.app/api/v1/x402/permissions"
payload = {
"resource": {
"url": "https://myagent.ai/api/v1/tasks",
"description": "AI agent task execution"
},
"accepted": {
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "44742763076047497640080230236781474129970992727896593861997347135613135571071",
"extra": {
"agentId": "80918427023170428029540261117198154464497879145267720259488529685089104529015",
"httpVerb": "POST"
}
},
"delegationConfig": { "delegationId": "a1b2c3d4-e5f6-4a90-8bcd-ef1234567890" }
}
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({
resource: {url: 'https://myagent.ai/api/v1/tasks', description: 'AI agent task execution'},
accepted: {
scheme: 'nvm:erc4337',
network: 'eip155:84532',
planId: '44742763076047497640080230236781474129970992727896593861997347135613135571071',
extra: {
agentId: '80918427023170428029540261117198154464497879145267720259488529685089104529015',
httpVerb: 'POST'
}
},
delegationConfig: {delegationId: 'a1b2c3d4-e5f6-4a90-8bcd-ef1234567890'}
})
};
fetch('https://api.sandbox.nevermined.app/api/v1/x402/permissions', 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.sandbox.nevermined.app/api/v1/x402/permissions",
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([
'resource' => [
'url' => 'https://myagent.ai/api/v1/tasks',
'description' => 'AI agent task execution'
],
'accepted' => [
'scheme' => 'nvm:erc4337',
'network' => 'eip155:84532',
'planId' => '44742763076047497640080230236781474129970992727896593861997347135613135571071',
'extra' => [
'agentId' => '80918427023170428029540261117198154464497879145267720259488529685089104529015',
'httpVerb' => 'POST'
]
],
'delegationConfig' => [
'delegationId' => 'a1b2c3d4-e5f6-4a90-8bcd-ef1234567890'
]
]),
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.sandbox.nevermined.app/api/v1/x402/permissions"
payload := strings.NewReader("{\n \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\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.sandbox.nevermined.app/api/v1/x402/permissions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.nevermined.app/api/v1/x402/permissions")
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 \"resource\": {\n \"url\": \"https://myagent.ai/api/v1/tasks\",\n \"description\": \"AI agent task execution\"\n },\n \"accepted\": {\n \"scheme\": \"nvm:erc4337\",\n \"network\": \"eip155:84532\",\n \"planId\": \"44742763076047497640080230236781474129970992727896593861997347135613135571071\",\n \"extra\": {\n \"agentId\": \"80918427023170428029540261117198154464497879145267720259488529685089104529015\",\n \"httpVerb\": \"POST\"\n }\n },\n \"delegationConfig\": {\n \"delegationId\": \"a1b2c3d4-e5f6-4a90-8bcd-ef1234567890\"\n }\n}"
response = http.request(request)
puts response.read_body{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGFuSWQiOiI0MzI5ODQzMjk4NDMyOSIsImFnZW50SWQiOiIxMjM0NTY3ODkwMTIzNDU2Nzg5MCJ9.x402_signature_hash"
}Authorizations
Your Nevermined API Key (starts with 'nvm:'). Get one at nevermined.app under Settings > API Keys.
Body
The x402 PaymentPayload to mint a token for
Body of POST /x402/permissions (GenerateX402TokenDto) — an x402 PaymentPayload. accepted is the only field REQUEST VALIDATION requires: the handler runs a ValidationPipe, so a body without it is rejected with 400 before any handler logic runs. It is not the only field the API requires — every scheme handler additionally demands delegationConfig and accepted.planId, refusing the mint with BCK.X402.0030 (HTTP 402). There is no settlement-account field: for card schemes the seller's Stripe Connect account is resolved server-side from the plan and is never supplied by the caller.
The payment scheme you selected: nvm:erc4337 for crypto settlement, nvm:card-delegation for card settlement.
Show child attributes
Show child attributes
The protected resource this token is minted for. Optional — but on tokenVersion 3 an omitted resource.url is signed as the empty string, which binds the token to having no resource rather than to any resource.
Show child attributes
Show child attributes
Delegation configuration. REQUIRED by both schemes despite being absent from required above — the DTO marks it optional and the scheme handler refuses the mint with BCK.X402.0030 (HTTP 402). nvm:erc4337 needs either delegationId or the inline triple spendingLimitCents + durationSecs + currency; nvm:card-delegation accepts an empty object {}, which selects a card automatically (deprecated).
Show child attributes
Show child attributes
EIP-712 struct version to sign. A version 3 signature carries a one-time nonce, so the token is SINGLE-USE — it is consumed by its first settle and a second settle is refused with BCK.X402.0059; mint one token per paid request. A version 3 token is also bound to whichever of accepted.extra.agentId, resource.url and accepted.extra.httpVerb you send on this request, since each is signed as the empty string when omitted. Version 2 is the legacy shape: reusable and unbound, so a captured token replays until the permission or delegation is revoked — ask for it only if you cannot mint per request. When this field is omitted the server signs version 3, except for clients whose pinned API version is below 1.34 — that pin comes from the Nevermined-Version header, or, when no header is sent, from the version stamped on the API key when it was minted — which keep receiving version 2.
2, 3 3
Response
Permission created
Response of POST /x402/permissions. The endpoint returns the access token and nothing else — it does not return the permission hash, so read the new permission back off GET /x402/permissions.
x402 access token (JWT) for permission-based access. Used by the subscriber to call agent endpoints without exposing their private keys. The permission details (plan id, agent id, subscriber address, expiry, limits) are embedded in the token.
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGFuSWQiOiI0MzI5ODQzMjk4NDMyOSIsImFnZW50SWQiOiIxMjM0NTY3ODkwMTIzNDU2Nzg5MCJ9.x402_signature_hash"
Was this page helpful?