curl --request POST \
--url https://api.platform.dakota.xyz/mandates \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"payment_agent_id": "2vWxAgent0000000000000000000",
"rule": {
"target_type": "recipient",
"targets": [
"Alice"
],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}
'const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
payment_agent_id: '2vWxAgent0000000000000000000',
rule: {
target_type: 'recipient',
targets: ['Alice'],
network_id: 'base-sepolia',
asset: 'USDC',
max_per_tx: '100',
window: 'MONTHLY',
max_count_per_target_in_window: 1
},
valid_until: 1798761599
})
};
fetch('https://api.platform.dakota.xyz/mandates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.dakota.xyz/mandates"
payload = {
"payment_agent_id": "2vWxAgent0000000000000000000",
"rule": {
"target_type": "recipient",
"targets": ["Alice"],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.dakota.xyz/mandates"
payload := strings.NewReader("{\n \"payment_agent_id\": \"2vWxAgent0000000000000000000\",\n \"rule\": {\n \"target_type\": \"recipient\",\n \"targets\": [\n \"Alice\"\n ],\n \"network_id\": \"base-sepolia\",\n \"asset\": \"USDC\",\n \"max_per_tx\": \"100\",\n \"window\": \"MONTHLY\",\n \"max_count_per_target_in_window\": 1\n },\n \"valid_until\": 1798761599\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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))
}{
"id": "2vWxMandate00000000000000000",
"status": "pending",
"bound_signer_id": "2vWxSigner000000000000000000",
"rule": {
"target_type": "recipient",
"targets": [
"2vWxRecipient000000000000000"
],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}{
"type": "https://docs.dakota.xyz/api-reference/errors#invalid-request",
"title": "Invalid Request",
"status": 400,
"detail": "target \"Bob\": recipient not found for this customer"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Not Found",
"status": 404,
"detail": "agent not found"
}Create a mandate directly (BETA)
Beta — early access.
Drafts a PENDING mandate from a direct user interaction - no instruction back-link. Exactly one binding form names the signer the mandate binds: payment_agent_id (the hosted convenience - binds that agent’s signer and anchors the mandate to the agent’s customer), or signer_id together with customer_id (any of the client’s signers, BYO keys included; the customer anchors the recipient-target scope and the §8 approver set). The rule is the one the customer will approve (POST /mandates//approve, a recognized signer other than the bound one, §8). Recipient targets may be recipient ids or payee names - names resolve to the mandate’s customer’s existing recipients before anything is stored. Schedule payments under it by mandate_id; they arm the moment it activates.
curl --request POST \
--url https://api.platform.dakota.xyz/mandates \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"payment_agent_id": "2vWxAgent0000000000000000000",
"rule": {
"target_type": "recipient",
"targets": [
"Alice"
],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}
'const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
payment_agent_id: '2vWxAgent0000000000000000000',
rule: {
target_type: 'recipient',
targets: ['Alice'],
network_id: 'base-sepolia',
asset: 'USDC',
max_per_tx: '100',
window: 'MONTHLY',
max_count_per_target_in_window: 1
},
valid_until: 1798761599
})
};
fetch('https://api.platform.dakota.xyz/mandates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.dakota.xyz/mandates"
payload = {
"payment_agent_id": "2vWxAgent0000000000000000000",
"rule": {
"target_type": "recipient",
"targets": ["Alice"],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.dakota.xyz/mandates"
payload := strings.NewReader("{\n \"payment_agent_id\": \"2vWxAgent0000000000000000000\",\n \"rule\": {\n \"target_type\": \"recipient\",\n \"targets\": [\n \"Alice\"\n ],\n \"network_id\": \"base-sepolia\",\n \"asset\": \"USDC\",\n \"max_per_tx\": \"100\",\n \"window\": \"MONTHLY\",\n \"max_count_per_target_in_window\": 1\n },\n \"valid_until\": 1798761599\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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))
}{
"id": "2vWxMandate00000000000000000",
"status": "pending",
"bound_signer_id": "2vWxSigner000000000000000000",
"rule": {
"target_type": "recipient",
"targets": [
"2vWxRecipient000000000000000"
],
"network_id": "base-sepolia",
"asset": "USDC",
"max_per_tx": "100",
"window": "MONTHLY",
"max_count_per_target_in_window": 1
},
"valid_until": 1798761599
}{
"type": "https://docs.dakota.xyz/api-reference/errors#invalid-request",
"title": "Invalid Request",
"status": 400,
"detail": "target \"Bob\": recipient not found for this customer"
}{
"type": "https://docs.dakota.xyz/api-reference/errors#not-found",
"title": "Not Found",
"status": 404,
"detail": "agent not found"
}Authorizations
Body
Exactly one binding form is required - payment_agent_id alone, or signer_id together with customer_id. Any other combination is rejected with 400.
Show child attributes
Show child attributes
Binding form A (hosted convenience) - the mandate binds this agent's signer and anchors to the agent's customer. Mutually exclusive with signer_id/customer_id.
Binding form B - the mandate binds this signer directly (any of the client's signers, not only an agent's). Requires customer_id.
Binding form B - the customer the mandate is anchored to; must belong to the calling client. Defines the recipient-target scope and the §8 approver set (approval requires a recognized signer of THIS customer other than the bound one). Requires signer_id.
Response
The pending mandate, targets resolved to ids.
expired is DERIVED, never stored - a pending or active mandate whose valid_until has passed. It cannot authorize payments and cannot be approved; it can still be cancelled.
pending, active, expired, rejected, revoked, done The customer this mandate is anchored to - approval requires a recognized signer of this customer other than the bound one (§8), and recipient targets belong to it. Absent only on rows created before the anchor existed.
DERIVED, display-only - the rule's recipient targets resolved to names, parallel to rule.targets (raw id on a miss). Absent for address/any target kinds. The ids in the rule remain the grant.
The CURRENT version number (1 for a mandate that has never been amended). rule below is this version's rule — the one the gate governs on. Each version is immutable and independently signed; the full history is at GET /mandates/{mandate_id}/versions.
Show child attributes
Show child attributes
Unix time of the §8 approval; absent until approved.
The signer that cancelled the mandate while it was still pending (§8); absent otherwise.
The signer that cancelled the mandate after activation (§8); absent otherwise.
Was this page helpful?

