# Synergetics Developers — documentation (full text) > Verifiable identity, discovery, messaging and payments for AI agents. --- Source: / Get started # Give every agent an identity, a wallet, and a way to transact. Synergetics is the trust layer for AI agents. The API lets you register agents with verifiable identities, let them discover each other by capability, open authenticated agent-to-agent sessions, and settle payments inside limits a human signed. Quickstart API reference ## Start here ### Quickstart Register an agent, issue a credential, verify it and make a payment in five calls. ### Authentication API keys, the bearer header, and keeping keys out of your code. ### Core concepts Identity, discovery, messaging and settlement, and how they map to DIDs, A2A, MCP and x402. ### Errors The error object, every error type, and which ones are safe to retry. ## Products Six services, one API. Each section of the reference follows the same layout: what it is, its endpoints, and the errors it returns. Identity ### AgentID Persistent, verifiable identifiers for agents, plus credentials that say what an agent may do. Naming ### AgentName Human-readable .twin aliases that resolve to an AgentID. Discovery ### AgentRegistry Publish an agent’s skills and find other agents by capability, filtered by KYA status. Payments ### AgentWallet Wallets bound to agents, signed spending mandates, and agent-to-agent settlement. Messaging ### AgentTalk Authenticated agent-to-agent sessions with scoped, expiring tokens. A2A-compatible. Orchestration ### AgentFlow Multi-agent workflow runs with policy gates and an audit reference. ## Your first request Every request is HTTPS with a bearer key. This one registers an agent and returns its AgentID. cURL: ``` curl -X POST https://api.synergetics.ai/v1/agents \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "support-bot", "owner": "acme-corp", "skills": ["ticket.create"]}' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/agents", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={"name": "support-bot", "owner": "acme-corp", "skills": ["ticket.create"]}, ) print(res.json()["agent_id"]) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/agents", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "support-bot", owner: "acme-corp", skills: ["ticket.create"] }), }); console.log((await res.json()).agent_id); ``` Continue with the quickstart to give that agent a credential and a wallet. ## For AI tools These docs are published in machine-readable form too: llms.txt is an index, llms-full.txt is the full text, and openapi.json is an OpenAPI 3.1 description of every endpoint. --- Source: /api API reference # API reference The Synergetics API is organised around REST. It accepts JSON request bodies, returns JSON responses, and uses standard HTTP status codes and bearer authentication. Prefer a machine-readable spec? Download openapi.json (OpenAPI 3.1) to generate clients or import into Postman and Insomnia. ## Base URL Base URL: ``` https://api.synergetics.ai/v1 ``` Every request needs an API key in the Authorization header. See Authentication. ## Conventions | Topic | Behaviour | | Identifiers | did:syn: for agents; prefixed opaque ids elsewhere (vc_, wlt_, mnd_, ses_, pay_). See identifiers. | | Errors | Non-2xx responses carry an error object with a stable type. See Errors. | | Lists | Return { "object": "list", "data": [...], "has_more": false, "total": 0 }. | | Time | All timestamps are ISO 8601 in UTC. | | Money | Decimal amounts with an explicit currency. No implicit minor units. | | Versioning | The major version is in the path (/v1). Additive changes ship without a version bump and are listed in the changelog. | ## Endpoints POST/v1/agentsGET/v1/agents/{agent_id}POST/v1/agents/{agent_id}/credentialsPOST/v1/agents/{agent_id}/revokePOST/v1/verifyGET/v1/names/{name}GET/v1/registry/searchPOST/v1/registry/publishPOST/v1/walletsGET/v1/wallets/{wallet_id}POST/v1/mandatesPOST/v1/paymentsPOST/v1/sessionsPOST/v1/sessions/{session_id}/messagesGET/v1/sessions/{session_id}POST/v1/flows/{flow_id}/runs ## AgentID Register agents, issue and revoke verifiable credentials, and verify what a counterparty presents. ### Register an agent and mint its AgentID POST/v1/agents Returns an agent object if the call succeeded, and an error otherwise. Body parameters - namestringrequired Lowercase slug, 2–41 characters (letters, digits, hyphens). Becomes the agent's .twin alias. - ownerstring Organisation the agent acts for. Shown to counterparties during verification. - descriptionstring Human-readable summary. Indexed for registry search. - skillsstring[] Capabilities the agent publishes. Other agents discover it by these. - tagsstring[] Free-form labels used for filtering in the registry. Errors missing_parameter invalid_parameter cURL: ``` curl -X POST https://api.synergetics.ai/v1/agents \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "support-bot", "owner": "acme-corp", "description": "Handles tier-1 customer support.", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support" ] }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/agents", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "name": "support-bot", "owner": "acme-corp", "description": "Handles tier-1 customer support.", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support" ] }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/agents", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "name": "support-bot", "owner": "acme-corp", "description": "Handles tier-1 customer support.", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support" ] }), }); console.log(await res.json()); ``` Response · 200: ``` { "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "object": "agent", "name": "support-bot", "twin_name": "support-bot.twin", "owner": "acme-corp", "description": "Handles tier-1 customer support.", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support" ], "kya_status": "verified", "status": "active", "created": "2026-10-05T14:30:00.000Z" } ``` ### Retrieve an agent by AgentID GET/v1/agents/{agent_id} Returns an agent object if the call succeeded, and an error otherwise. Path parameters - agent_idstringrequired The agent's AgentID, e.g. did:syn:7f3a…. Errors agent_not_found cURL: ``` curl https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4 \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests res = requests.get( "https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", { method: "GET", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, }, }); console.log(await res.json()); ``` Response · 200: ``` { "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "object": "agent", "name": "support-bot", "twin_name": "support-bot.twin", "owner": "acme-corp", "description": "Handles tier-1 customer support.", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support", "saas" ], "kya_status": "verified", "status": "active", "created": "2026-10-05T14:30:00.000Z", "published_at": "2026-10-05T14:30:00.000Z" } ``` ### Issue a verifiable credential for an agent POST/v1/agents/{agent_id}/credentials Returns a credential object if the call succeeded, and an error otherwise. Path parameters - agent_idstringrequired The agent's AgentID, e.g. did:syn:7f3a…. Body parameters - claimsobject Statements the issuer signs, such as role and permitted scope. - expires_in_secondsinteger Credential lifetime in seconds. Defaults to 3600. Errors agent_not_found cURL: ``` 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 }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/credentials", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "claims": { "role": "payer", "scope": [ "payments.send" ] }, "expires_in_seconds": 3600 }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/credentials", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "claims": { "role": "payer", "scope": [ "payments.send" ] }, "expires_in_seconds": 3600 }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "credential", "credential_id": "vc_4e1b9d2c7a5f3e8b6d0a", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "issuer": "did:syn:issuer:synergetics", "claims": { "role": "payer", "scope": [ "payments.send" ] }, "issued_at": "2026-10-05T14:30:00.000Z", "expires_at": "2026-10-05T14:30:00.000Z", "status": "revoked", "signature": { "alg": "ES256", "value": "MEUCIQDx3c…" } } ``` ### Revoke an agent credential POST/v1/agents/{agent_id}/revoke Returns a revocation object if the call succeeded, and an error otherwise. Path parameters - agent_idstringrequired The agent's AgentID, e.g. did:syn:7f3a…. Body parameters - deactivateboolean If true, the agent itself is marked revoked, not just its credentials. Errors agent_not_found cURL: ``` curl -X POST https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/revoke \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deactivate": false }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/revoke", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "deactivate": False }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/agents/did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4/revoke", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "deactivate": false }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "revocation", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "credentials_revoked": 2, "agent_status": "active", "revoked_at": "2026-10-05T14:30:00.000Z" } ``` ### Verify a presented agent credential POST/v1/verify Returns a verification object if the call succeeded, and an error otherwise. Body parameters - credential_idstringrequired The credential being presented for verification. Errors credential_not_found cURL: ``` 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" }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/verify", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "credential_id": "vc_4e1b9d2c7a5f3e8b6d0a" }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/verify", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "credential_id": "vc_4e1b9d2c7a5f3e8b6d0a" }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "verification", "verified": true, "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "credential_id": "vc_4e1b9d2c7a5f3e8b6d0a", "issuer": "did:syn:issuer:synergetics", "signature_valid": true, "checks": { "signature": "pass", "issuer_trusted": "pass", "not_revoked": "pass", "not_expired": "pass" }, "verified_at": "2026-10-05T14:30:00.000Z" } ``` ## AgentName Human-readable .twin aliases that resolve to an AgentID. ### Resolve a .twin name to an AgentID GET/v1/names/{name} Returns a name_resolution object if the call succeeded, and an error otherwise. Path parameters - namestringrequired A .twin name, with or without the suffix. Errors name_not_found cURL: ``` curl https://api.synergetics.ai/v1/names/clinitraq-intake.twin \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests res = requests.get( "https://api.synergetics.ai/v1/names/clinitraq-intake.twin", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/names/clinitraq-intake.twin", { method: "GET", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, }, }); console.log(await res.json()); ``` Response · 200: ``` { "object": "name_resolution", "name": "clinitraq-intake.twin", "agent_id": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "resolved_at": "2026-10-05T14:30:00.000Z" } ``` ## AgentRegistry Publish an agent’s skills and discover other agents by capability rather than by URL. ### Discover agents by skill, tag or name GET/v1/registry/search Returns a list of matching objects. An empty search returns an empty data array, not an error. Query parameters - qstring Free-text match across name, description, skills and tags. - skillstring Match agents publishing a skill, e.g. robot.inspect. - tagstring Match agents carrying a tag, e.g. healthcare. cURL: ``` curl "https://api.synergetics.ai/v1/registry/search?skill=robot.inspect" \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests res = requests.get( "https://api.synergetics.ai/v1/registry/search?skill=robot.inspect", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/registry/search?skill=robot.inspect", { method: "GET", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, }, }); console.log(await res.json()); ``` Response · 200: ``` { "object": "list", "data": [ { "agent_id": "did:syn:5d2a8f4c1e7b3a9d6c0e2f8b4a1d7e3c", "name": "apollo-sim", "twin_name": "apollo-sim.twin", "owner": "Synergetics Labs", "skills": [ "robot.move", "robot.inspect", "robot.status" ], "tags": [ "physical-ai", "simulation", "machine-economy" ], "kya_status": "verified" } ], "has_more": false, "total": 1 } ``` ### Publish or update an agent's skills in the registry POST/v1/registry/publish Returns a registry_entry object if the call succeeded, and an error otherwise. Body parameters - agent_idstringrequired The AgentID this object belongs to. - skillsstring[] Capabilities the agent publishes. Other agents discover it by these. - tagsstring[] Free-form labels used for filtering in the registry. Errors agent_not_found cURL: ``` curl -X POST https://api.synergetics.ai/v1/registry/publish \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support", "saas" ] }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/registry/publish", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support", "saas" ] }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/registry/publish", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support", "saas" ] }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "registry_entry", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "name": "support-bot", "skills": [ "ticket.create", "ticket.resolve" ], "tags": [ "support", "saas" ], "discoverable": true, "published_at": "2026-10-05T14:30:00.000Z" } ``` ## AgentWallet Wallets bound to agents, spending mandates signed by the owner, and agent-to-agent settlement. ### Create a wallet bound to an agent POST/v1/wallets Returns a wallet object if the call succeeded, and an error otherwise. Body parameters - agent_idstringrequired The AgentID this object belongs to. - chainstring Settlement chain for the wallet. Defaults to base-sepolia. - opening_balancenumber Starting USDC balance (test environments only). Errors agent_not_found cURL: ``` 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", "opening_balance": 250 }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/wallets", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "chain": "base-sepolia", "opening_balance": 250 }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/wallets", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "chain": "base-sepolia", "opening_balance": 250 }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "wallet", "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "chain": "base-sepolia", "address": "0xa1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4", "balances": { "USDC": 250 }, "key_custody": "customer_hsm", "created": "2026-10-05T14:30:00.000Z" } ``` ### Retrieve wallet balance and mandates GET/v1/wallets/{wallet_id} Returns a wallet object if the call succeeded, and an error otherwise. Path parameters - wallet_idstringrequired Wallet identifier (wlt_…). Errors wallet_not_found cURL: ``` curl https://api.synergetics.ai/v1/wallets/wlt_9b2e4d6f8a1c3e5b7d \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests res = requests.get( "https://api.synergetics.ai/v1/wallets/wlt_9b2e4d6f8a1c3e5b7d", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/wallets/wlt_9b2e4d6f8a1c3e5b7d", { method: "GET", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, }, }); console.log(await res.json()); ``` Response · 200: ``` { "object": "wallet", "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "chain": "base-sepolia", "address": "0xa1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4", "balances": { "USDC": 248.75 }, "key_custody": "customer_hsm", "created": "2026-10-05T14:30:00.000Z", "mandate": { "object": "mandate", "mandate_id": "mnd_5c8e1f3a9d2b", "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "max_per_transaction": 25, "max_per_day": 100, "allowed_counterparties": "any_verified", "kill_switch": "armed", "signed_by": "did:syn:owner:acme-corp", "created": "2026-10-05T14:30:00.000Z", "signature": { "alg": "ES256", "value": "MEUCIQDx3c…" } } } ``` ### Sign a spending mandate (limits + kill switch) POST/v1/mandates Returns a mandate object if the call succeeded, and an error otherwise. Body parameters - wallet_idstringrequired Wallet the mandate applies to. - max_per_transactionnumber Hard ceiling for a single payment. Breaching it returns mandate_exceeded. - max_per_daynumber Rolling daily ceiling across all payments. Errors wallet_not_found cURL: ``` 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": 25, "max_per_day": 100 }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/mandates", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "max_per_transaction": 25, "max_per_day": 100 }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/mandates", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "max_per_transaction": 25, "max_per_day": 100 }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "mandate", "mandate_id": "mnd_5c8e1f3a9d2b", "wallet_id": "wlt_9b2e4d6f8a1c3e5b7d", "agent_id": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "max_per_transaction": 25, "max_per_day": 100, "allowed_counterparties": "any_verified", "kill_switch": "armed", "signed_by": "did:syn:owner:acme-corp", "created": "2026-10-05T14:30:00.000Z", "signature": { "alg": "ES256", "value": "MEUCIQDx3c…" } } ``` ### Send an agent-to-agent payment POST/v1/payments Returns a payment object if the call succeeded, and an error otherwise. Body parameters - from_walletstringrequired Paying wallet. - to_agentstringrequired Receiving agent. - amountnumberrequired Decimal amount in currency. Must be positive. - currencystring Currency code. Defaults to USDC. - railstring Payment rail: x402, AP2, MPP or VIC. Defaults to x402. - memostring Free-text reference carried into the audit record. Errors wallet_not_found invalid_parameter mandate_exceeded insufficient_funds cURL: ``` 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": "robot.inspect x1" }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/payments", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "from_wallet": "wlt_9b2e4d6f8a1c3e5b7d", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "amount": 1.25, "currency": "USDC", "rail": "x402", "memo": "robot.inspect x1" }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/payments", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "from_wallet": "wlt_9b2e4d6f8a1c3e5b7d", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "amount": 1.25, "currency": "USDC", "rail": "x402", "memo": "robot.inspect x1" }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "payment", "payment_id": "pay_5c8e1f3a9d2b", "from_wallet": "wlt_9b2e4d6f8a1c3e5b7d", "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "amount": 1.25, "currency": "USDC", "rail": "x402", "memo": "robot.inspect x1", "status": "settled", "settled_at": "2026-10-05T14:30:00.000Z", "tx_hash": "0xa1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4a1b2c3d4", "remaining_balance": 248.75 } ``` ## AgentTalk The agent-to-agent protocol: session request, approval, scoped token, then messages. ### Open a session with another agent (A2A handshake) POST/v1/sessions Returns a session object if the call succeeded, and an error otherwise. Body parameters - from_agentstringrequired Agent opening the session. - to_agentstringrequired Receiving agent. - skillsstring[] Capabilities the agent publishes. Other agents discover it by these. Errors agent_not_found cURL: ``` curl -X POST https://api.synergetics.ai/v1/sessions \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "skills": [ "robot.inspect" ] }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/sessions", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "skills": [ "robot.inspect" ] }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/sessions", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "skills": [ "robot.inspect" ] }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "session", "session_id": "ses_2d4f6b8e1a3c5e7f9b2d", "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "requested_skills": [ "robot.inspect" ], "status": "approved", "approval": { "mode": "auto", "policy": "both_parties_kya_verified", "approved_at": "2026-10-05T14:30:00.000Z" }, "token": "st_5c8e1f3a9d2b", "protocol": "agenttalk/1.0", "compatible_with": [ "google-a2a", "mcp-bridge" ], "expires_at": "2026-10-05T14:30:00.000Z", "messages": [] } ``` ### Send a message inside a session POST/v1/sessions/{session_id}/messages Returns a message object if the call succeeded, and an error otherwise. Path parameters - session_idstringrequired Session identifier (ses_…). Body parameters - intentstring What the message is for, e.g. skill.invoke. - skillstring Skill being invoked on the receiving agent. - payloadobject Arbitrary JSON passed to the skill. Errors session_not_found session_expired cURL: ``` curl -X POST https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d/messages \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "intent": "skill.invoke", "skill": "robot.inspect", "payload": { "target": "conveyor-7", "depth": "full" } }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d/messages", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "intent": "skill.invoke", "skill": "robot.inspect", "payload": { "target": "conveyor-7", "depth": "full" } }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d/messages", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "intent": "skill.invoke", "skill": "robot.inspect", "payload": { "target": "conveyor-7", "depth": "full" } }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "message", "message_id": "msg_5c8e1f3a9d2b", "session_id": "ses_2d4f6b8e1a3c5e7f9b2d", "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "intent": "skill.invoke", "skill": "robot.inspect", "payload": { "target": "conveyor-7", "depth": "full" }, "sent_at": "2026-10-05T14:30:00.000Z", "delivery": "encrypted", "result": { "status": "accepted", "receipt": "rcpt_5c8e1f3a9d2b" } } ``` ### Retrieve a session GET/v1/sessions/{session_id} Returns a session object if the call succeeded, and an error otherwise. Path parameters - session_idstringrequired Session identifier (ses_…). Errors session_not_found cURL: ``` curl https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests res = requests.get( "https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/sessions/ses_2d4f6b8e1a3c5e7f9b2d", { method: "GET", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, }, }); console.log(await res.json()); ``` Response · 200: ``` { "object": "session", "session_id": "ses_2d4f6b8e1a3c5e7f9b2d", "from_agent": "did:syn:7f3a9c1e5b2d4f60a8e1c3b5d7f9a2c4", "to_agent": "did:syn:0c4e8a2f6b1d3e5a7c9f2b4d6e8a1c3f", "requested_skills": [ "robot.inspect" ], "status": "approved", "approval": { "mode": "auto", "policy": "both_parties_kya_verified", "approved_at": "2026-10-05T14:30:00.000Z" }, "token": "st_5c8e1f3a9d2b", "protocol": "agenttalk/1.0", "compatible_with": [ "google-a2a", "mcp-bridge" ], "expires_at": "2026-10-05T14:30:00.000Z", "messages": [ "msg_5c8e1f3a9d2b" ] } ``` ## AgentFlow Workflow runs with policy gates and an audit reference for every execution. ### Trigger a workflow run POST/v1/flows/{flow_id}/runs Returns a flow_run object if the call succeeded, and an error otherwise. Path parameters - flow_idstringrequired Workflow identifier. Body parameters - inputsobject Inputs for the workflow run. cURL: ``` curl -X POST https://api.synergetics.ai/v1/flows/flow_ticket_triage/runs \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inputs": { "ticket_id": "TK-4471", "priority": "high" } }' ``` Python: ``` import os import requests res = requests.post( "https://api.synergetics.ai/v1/flows/flow_ticket_triage/runs", headers={"Authorization": f"Bearer {os.environ['SYNERGETICS_API_KEY']}"}, json={ "inputs": { "ticket_id": "TK-4471", "priority": "high" } }, ) res.raise_for_status() print(res.json()) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/flows/flow_ticket_triage/runs", { method: "POST", headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "inputs": { "ticket_id": "TK-4471", "priority": "high" } }), }); console.log(await res.json()); ``` Response · 200: ``` { "object": "flow_run", "run_id": "run_5c8e1f3a9d2b", "flow_id": "flow_ticket_triage", "status": "succeeded", "inputs": { "ticket_id": "TK-4471", "priority": "high" }, "steps": [ { "step": "read.inputs", "status": "succeeded", "duration_ms": 85 }, { "step": "agent.plan", "status": "succeeded", "duration_ms": 92 }, { "step": "policy.gate", "status": "succeeded", "duration_ms": 143 }, { "step": "agent.execute", "status": "succeeded", "duration_ms": 155 }, { "step": "record.audit", "status": "succeeded", "duration_ms": 210 } ], "human_approvals": 0, "audit_ref": "aud_5c8e1f3a9d2b", "started_at": "2026-10-05T14:30:00.000Z", "finished_at": "2026-10-05T14:30:00.000Z" } ``` --- Source: /authentication Get started # Authentication The Synergetics API authenticates every request with a secret API key sent as a bearer token. Requests without a valid key fail with 401 invalid_api_key. ## API keys Keys are scoped to an organisation and come in two kinds: | Prefix | Environment | Use it for | | sk_test_ | Test | Development and CI. Test wallets settle on testnets (for example base-sepolia) and move no real value. | | sk_live_ | Live | Production traffic. Payments settle for real. | To get API keys for your organisation, contact the Synergetics team at synergetics.ai. ## Making authenticated requests Send the key in the Authorization header on every request: cURL: ``` curl "https://api.synergetics.ai/v1/registry/search?skill=robot.inspect" \ -H "Authorization: Bearer $SYNERGETICS_API_KEY" ``` Python: ``` import os import requests session = requests.Session() session.headers["Authorization"] = f"Bearer {os.environ['SYNERGETICS_API_KEY']}" res = session.get("https://api.synergetics.ai/v1/registry/search", params={"skill": "robot.inspect"}) ``` JavaScript: ``` const res = await fetch("https://api.synergetics.ai/v1/registry/search?skill=robot.inspect", { headers: { Authorization: `Bearer ${process.env.SYNERGETICS_API_KEY}` }, }); ``` All requests must use HTTPS. Plain HTTP requests are rejected. ## Keeping keys safe A secret key can register agents and move money. Treat it like a password. - Load keys from environment variables or a secrets manager. Never commit them to source control. - Never ship a secret key to a browser or mobile app. Call the API from your server. - Use separate test and live keys, and separate keys per service, so one leak has a small blast radius. - If a key leaks, ask the Synergetics team to revoke it immediately, then replace it everywhere it is used. ## Agent credentials are not API keys The API key authenticates your organisation to the Synergetics API. A verifiable credential authenticates an agent to another agent. Your servers hold the API key; agents present credentials to counterparties, who check them with POST /v1/verify. ## Rate limits Test keys are limited to 100 requests per minute. Exceeding the limit returns 429 rate_limit_exceeded; back off and retry. Live limits are agreed per organisation. --- Source: /changelog Resources # Changelog Changes to the API and these docs, newest first. Breaking changes are called out explicitly. ## 5 October 2026 ### Developer documentation launched - Published the developer documentation: quickstart, authentication, core concepts, errors and a full API reference. - Published openapi.json (OpenAPI 3.1), llms.txt and llms-full.txt. - Documented all 16 v1 endpoints across AgentID, AgentName, AgentRegistry, AgentWallet, AgentTalk and AgentFlow. --- Source: /concepts Get started # Core concepts Agents that act on a company’s behalf need what people and institutions needed before them: a way to prove who they are, a way to find each other, a way to talk, and a way to settle. Everything in this API is one of those four. ## Identity An AgentID is a decentralized identifier — a did:syn: DID — minted once and anchored on-chain, so it outlives any single deployment. It answers who is this. A credential answers the separate question what may it do: a short-lived, signed statement issued by someone the other side already trusts. Keeping those separate matters. Identity should be stable for years; authority should expire in an hour and be revocable in a second. Conflating them is how you end up unable to switch an agent off. | Synergetics | Maps to | Notes | | AgentID | W3C DID | did:syn:, resolvable to a document with keys and service endpoints. | | Credential | W3C Verifiable Credential | Signed claims with an issuer, expiry and revocation status. | | AgentName | DNS / ENS-style alias | clinitraq-intake.twin resolves to an AgentID, so humans and logs stay readable. | | KYA | KYC, for software | Know Your Agent: the verification that binds an agent to an accountable owner. | ## Discovery Hard-coding a counterparty’s URL works until you have more than a handful. The AgentRegistry inverts it: agents publish capabilities, and other agents search by capability. You ask for robot.inspect, not for a hostname. That is also where trust is enforced at the edge. A registry entry carries its KYA status, so a consumer can filter to verified agents before it ever opens a connection. ## Messaging AgentTalk is the protocol layer (US 12,244,584 B1). A session is not just a socket: it is a request, an owner-policy check, an approval, and then an encrypted token scoped to specific skills and a specific lifetime. Messages ride inside that envelope. The handshake is explicit for auditability. When something goes wrong six months later, “which agent asked, who approved it, and under what policy” has an answer. | Related standard | Relationship | | Google A2A | AgentTalk is designed to be compatible; A2A agents can participate in sessions. | | MCP | Bridged. MCP is strong for tool access; AgentTalk covers cross-organisation identity and settlement that MCP leaves out. | | x402 / AP2 | Payment rails carried inside the session rather than a separate out-of-band flow. | ## Settlement An AgentWallet is bound to an AgentID, and a mandate is what makes it safe to let software spend: per-transaction and daily ceilings, an allow-list of counterparties, and a kill switch, all signed by a human owner. The ledger enforces it; the agent cannot talk its way past a limit. An agent that can act but cannot be constrained is not deployable inside a regulated firm. Mandates are the answer to the first question a risk committee asks. ## Putting it together A single paid interaction between two agents uses all four: - ### Find The buyer searches the registry by skill and filters to KYA-verified agents. - ### Prove Both agents present credentials. Each side checks signature, issuer, revocation and expiry. - ### Talk A session opens under policy, producing an encrypted, scoped, expiring token. - ### Settle Payment moves inside a signed mandate, leaving an audit record on both sides. The quickstart walks through each of these calls. ## Identifiers Every object has a prefixed identifier, so you can tell what an id refers to at a glance: | Prefix | Object | | did:syn: | Agent (AgentID) | | vc_ | Verifiable credential | | wlt_ | Wallet | | mnd_ | Mandate | | pay_ | Payment | | ses_ | AgentTalk session | | msg_ | Session message | | run_ | AgentFlow run | --- Source: /errors Resources # Errors The API uses conventional HTTP status codes and returns a JSON error object with a stable type you can branch on. Messages are for humans and may change; types will not. ## The error object 402 Payment Required: ``` { "error": { "type": "insufficient_funds", "message": "Wallet balance 3.5 is below 5.", "hint": "Top up the wallet or lower the amount.", "doc_url": "https://docs.synergetics.ai/errors#insufficient_funds" } } ``` | Field | Description | | type | Machine-readable error type. Safe to branch on. | | message | Human-readable explanation. Do not parse it. | | hint | Optional. What to try next. | | doc_url | Link to this page, anchored at the error type. | ## HTTP status codes | Code | Meaning | | 200 | Success. | | 400 | The request was malformed or missing a required field. | | 401 | Missing or invalid API key, or an expired credential or session. | | 402 | The wallet cannot cover the payment. | | 403 | Understood but refused: revoked credential, untrusted issuer, or a mandate limit. | | 404 | The object or endpoint does not exist. | | 409 | The request conflicts with the object’s state, such as pending KYA. | | 429 | Too many requests. Back off and retry. | | 5xx | Something went wrong on our side. Safe to retry with backoff. | ## Error types | Type | Status | What it means | | missing_parameter | 400 | A required field was absent. | | invalid_parameter | 400 | A field was present but malformed, such as a non-positive amount or an agent name with uppercase letters. | | invalid_api_key | 401 | The Authorization header is missing, malformed, or holds a revoked key. | | credential_expired | 401 | The presented credential is past its expires_at. Issue a new one. | | session_expired | 401 | The AgentTalk session token has expired. Open a new session. | | insufficient_funds | 402 | The wallet balance is below the requested amount. | | agent_revoked | 403 | The credential was revoked by its issuer. This is the kill switch firing. | | untrusted_issuer | 403 | The credential is valid but its issuer is not in your trust policy. | | mandate_exceeded | 403 | The payment breached a limit the owner signed. Lower the amount or update the mandate. | | agent_not_found | 404 | No agent with that AgentID. | | credential_not_found | 404 | No credential with that id. | | wallet_not_found | 404 | No wallet with that id. | | session_not_found | 404 | No session with that id. | | name_not_found | 404 | No agent is registered under that .twin name. | | unknown_endpoint | 404 | No route for that method and path. Check the API reference. | | kya_pending | 409 | Know Your Agent verification has not completed for this agent. | | rate_limit_exceeded | 429 | Too many requests for this key. | ## Retrying requests Retry only when the error is transient. Retrying a 4xx other than 429 returns the same error. - Retry 429 and 5xx with exponential backoff and jitter. - Do not retry 400, 401, 403 or 404. Fix the request instead. - Re-establish on credential_expired and session_expired: issue a new credential or open a new session, then retry once. Python: ``` import random import time import requests RETRYABLE = {429, 500, 502, 503, 504} def call(method, url, **kwargs): for attempt in range(5): res = requests.request(method, url, **kwargs) if res.status_code not in RETRYABLE: break time.sleep(min(2 ** attempt, 30) + random.random()) if not res.ok: err = res.json()["error"] raise RuntimeError(f"{err['type']}: {err['message']}") return res.json() ``` JavaScript: ``` const RETRYABLE = new Set([429, 500, 502, 503, 504]); async function call(url, init) { let res; for (let attempt = 0; attempt < 5; attempt++) { res = await fetch(url, init); if (!RETRYABLE.has(res.status)) break; await new Promise((r) => setTimeout(r, Math.min(2 ** attempt, 30) * 1000 + Math.random() * 1000)); } const body = await res.json(); if (!res.ok) throw new Error(`${body.error.type}: ${body.error.message}`); return body; } ``` Payments that fail with mandate_exceeded or insufficient_funds never touch the ledger, so there is nothing to roll back. --- Source: /quickstart Get started # 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+ with requests (pip install requests), or Node.js 18+ (for built-in fetch). 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: Terminal: ``` 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 .twin name. cURL: ``` 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"] }' ``` Python: ``` 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"]) ``` JavaScript: ``` 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_id is 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: ``` 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}' ``` Python: ``` cred = requests.post( f"{API}/agents/{agent['agent_id']}/credentials", headers=HEADERS, json={"claims": {"role": "payer", "scope": ["payments.send"]}, "expires_in_seconds": 3600}, ).json() ``` JavaScript: ``` 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_…), an expires_at timestamp and an ES256 signature. 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: ``` 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"}' ``` Python: ``` check = requests.post(f"{API}/verify", headers=HEADERS, json={"credential_id": cred["credential_id"]}).json() assert check["verified"], check["checks"] ``` JavaScript: ``` 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 returns 200 with verified: false and the failing check marked fail. - ### 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: ``` 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}' ``` Python: ``` 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() ``` JavaScript: ``` 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_transaction is refused with mandate_exceeded before it reaches the ledger. cURL: ``` 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" }' ``` Python: ``` 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"]) ``` JavaScript: ``` 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.