Quickstart
Five calls, from nothing to a settled agent-to-agent payment. By the end you will have a registered agent with a verifiable credential and a wallet that can only spend inside a signed mandate.
#Before you begin
- An API key. See Authentication.
- One of:
curl, Python 3.9+ withrequests(pip install requests), or Node.js 18+ (for built-infetch).
The JavaScript examples use top-level await. Save them in a .mjs file and run node quickstart.mjs, or wrap them in an async function.
Export your key so the examples can read it:
export SYNERGETICS_API_KEY="sk_test_..."#Steps
#Register an agent
Minting an AgentID gives the agent a persistent identifier other parties can resolve and verify. It also reserves a human-readable
.twinname.curl -X POST https://api.synergetics.ai/v1/agents \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "report-reader", "owner": "acme-corp", "description": "Reads inspection reports and pays for them.", "skills": ["report.read"] }'import os import requests API = "https://api.synergetics.ai/v1" HEADERS = {"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"} agent = requests.post(f"{API}/agents", headers=HEADERS, json={ "name": "report-reader", "owner": "acme-corp", "description": "Reads inspection reports and pays for them.", "skills": ["report.read"], }).json() print(agent["agent_id"])const API = "https://api.synergetics.ai/v1"; const headers = { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }; const agent = await fetch(`${API}/agents`, { method: "POST", headers, body: JSON.stringify({ name: "report-reader", owner: "acme-corp", description: "Reads inspection reports and pays for them.", skills: ["report.read"], }), }).then((r) => r.json()); console.log(agent.agent_id);Response{ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "object": "agent", "name": "report-reader", "twin_name": "report-reader.twin", "owner": "acme-corp", "kya_status": "verified", "status": "active", "created": "2026-10-05T14:30:00.000Z" }The
agent_idis a DID. Keep it — every later call needs it.#Issue a verifiable credential
An AgentID says who the agent is. A credential says what it may do: signed claims with an issuer and an expiry that anyone can check.
curl -X POST https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/credentials \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"claims": {"role": "payer", "scope": ["payments.send"]}, "expires_in_seconds": 3600}'cred = requests.post( f"{API}/agents/{agent['agent_id']}/credentials", headers=HEADERS, json={"claims": {"role": "payer", "scope": ["payments.send"]}, "expires_in_seconds": 3600}, ).json()const cred = await fetch(`${API}/agents/${agent.agent_id}/credentials`, { method: "POST", headers, body: JSON.stringify({ claims: { role: "payer", scope: ["payments.send"] }, expires_in_seconds: 3600 }), }).then((r) => r.json());The response includes a
credential_id(vc_…), anexpires_attimestamp and an ES256signature. Credentials are short-lived on purpose.#Verify it the way a counterparty would
This is the call the other side makes before agreeing to do anything. It runs four independent checks: signature, issuer trust, revocation and expiry.
curl -X POST https://api.synergetics.ai/v1/verify \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"credential_id": "vc_4e1b9d2c7a5f3e8b6d0a"}'check = requests.post(f"{API}/verify", headers=HEADERS, json={"credential_id": cred["credential_id"]}).json() assert check["verified"], check["checks"]const check = await fetch(`${API}/verify`, { method: "POST", headers, body: JSON.stringify({ credential_id: cred.credential_id }), }).then((r) => r.json()); if (!check.verified) throw new Error(JSON.stringify(check.checks));Response{ "object": "verification", "verified": true, "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "credential_id": "vc_4e1b9d2c7a5f3e8b6d0a", "checks": { "signature": "pass", "issuer_trusted": "pass", "not_revoked": "pass", "not_expired": "pass" } }Always branch on
verified, not on the HTTP status. A revoked or expired credential still returns200withverified: falseand the failing check markedfail.#Create a wallet and sign a mandate
The wallet holds value. The mandate is what makes it safe to let software spend: per-transaction and daily limits signed by the owner, with a kill switch.
curl -X POST https://api.synergetics.ai/v1/wallets \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "chain": "base-sepolia"}' curl -X POST https://api.synergetics.ai/v1/mandates \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "max_per_transaction": 5, "max_per_day": 50}'wallet = requests.post(f"{API}/wallets", headers=HEADERS, json={"agent_id": agent["agent_id"], "chain": "base-sepolia"}).json() mandate = requests.post(f"{API}/mandates", headers=HEADERS, json={ "wallet_id": wallet["wallet_id"], "max_per_transaction": 5, "max_per_day": 50, }).json()const wallet = await fetch(`${API}/wallets`, { method: "POST", headers, body: JSON.stringify({ agent_id: agent.agent_id, chain: "base-sepolia" }), }).then((r) => r.json()); const mandate = await fetch(`${API}/mandates`, { method: "POST", headers, body: JSON.stringify({ wallet_id: wallet.wallet_id, max_per_transaction: 5, max_per_day: 50 }), }).then((r) => r.json());#Pay another agent
Send a payment over the x402 rail, inside the mandate. Anything above
max_per_transactionis refused withmandate_exceededbefore it reaches the ledger.curl -X POST https://api.synergetics.ai/v1/payments \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from_wallet": "wlt_9b2e4d6f8a1c3e5b7d", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "amount": 1.25, "currency": "USDC", "rail": "x402", "memo": "inspection report" }'payment = requests.post(f"{API}/payments", headers=HEADERS, json={ "from_wallet": wallet["wallet_id"], "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "amount": 1.25, "currency": "USDC", "rail": "x402", "memo": "inspection report", }).json() print(payment["status"], payment["remaining_balance"])const payment = await fetch(`${API}/payments`, { method: "POST", headers, body: JSON.stringify({ from_wallet: wallet.wallet_id, to_agent: "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", amount: 1.25, currency: "USDC", rail: "x402", memo: "inspection report", }), }).then((r) => r.json()); console.log(payment.status, payment.remaining_balance);Response{ "object": "payment", "payment_id": "pay_5c8e1f3a9d2b", "amount": 1.25, "currency": "USDC", "rail": "x402", "status": "settled", "remaining_balance": 248.75 }
#What you built
That is the whole loop: identity → credential → verification → mandate → settlement. The rest of the API builds on those five ideas.
#Next steps
Core concepts
Why identity and authority are separate, and how mandates constrain spending.
Open an AgentTalk session
Discover a counterparty in the registry and invoke one of its skills.
API reference
Every endpoint, parameter and example response.
Handle errors
Error types, status codes and retry guidance.