Bindagt documentation
Anyone can build a bot and claim it works for your company, and today there is no way to check. Bindagt gives every agent a permanent address under a domain you control — agt://acme.com/support-bot — recorded where nobody, including us, can quietly change it. Anyone can then confirm that address, free and without an account. It is built on AGT-9303, a standard we wrote and published in full.
This guide takes you from installing the SDK to anchoring and verifying your first agent.
Quickstart
Install the SDK and verify any agent in under a minute. Verification reads the registry directly — no API key, no account.
1. Install
2. Verify an agent
const result = await verifyOnChain('agt://acme.com/support-bot');
if (result.valid) {
console.log(result.domain, result.anchoredAt);
}
That's it. The call returns the agent's resolved status and metadata, read straight from the registry.
Core concepts
Roots
A root — what the rest of this site calls your domain registration — is the entry that binds a domain you control to Bindagt, for example agt://acme.com. Control is proven by DNS: you publish a TXT record and we read it directly from your domain's authoritative nameservers. A root is required before you can anchor agents.
Agents
An agent is an identity recorded — "anchored", in the standard's wording — under a root, such as agt://acme.com/support-bot. Each agent record cannot be altered for its term and can be transferred when ownership changes. Your root includes your first agent; further agents are bought in packs of slots that never expire.
Verification
Anyone can verify an agent by resolving its identifier against the registry. Verification requires no account and carries no charge, and works independently of Bindagt's own servers.
Possession
Verification answers does this agent exist, and is its root in good standing. It does not answer is the thing calling me actually that agent — and it cannot, because an agent's identity document is public by design. Anyone can download it.
That second question is answered by possession: a signature over the specific request being made, produced with the domain's control key and checked against the key recorded on L1. It is scoped to that one request and expires in sixty seconds, so a captured signature cannot be replayed elsewhere or later.
The two together are what makes an identity here different from a bearer credential. Holding the document is not holding the identity. This is §7.3 of the standard, and it is mandatory from AGT-9303:1.7 onwards — a verifier is required to treat anything declaring less as identified but not proven, and may refuse it.
Register an agent
Registration happens through your Bindagt account or the CLI. The flow is:
- Register a root for a domain you control and complete DNS verification.
- Anchor an agent under that root with a name of your choosing.
- The agent's identity is written to the registry and is immediately verifiable.
// and records your first agent under the domain
$ npx bindagt register agt://acme.com/support-bot
Verify an agent
There are two ways to verify, both free. Each returns a VerifyResult — an object with valid, domain, domainStatus, anchoredAt and related fields.
verify() — convenience
Resolves an identifier through the Bindagt API (cached, faster at scale) and returns the result.
// → { valid, domain, domainStatus, agentType, anchoredAt, ... }
verifyOnChain() — fully independent
Reads the public record directly, without passing through any Bindagt server, so the check keeps working even if our services are offline.
// → VerifyResult, read from L1 directly, at $0
if (result.valid) { /* trusted */ }
Integrate your agent
Once your agent is anchored, it can present its identity to other systems — and check the identity of agents that call it. For agents built on the OpenAI Agents SDK, the @bindagt/openai plugin does both.
Present your identity on outbound calls
presentAs() returns a drop-in fetch. Every request made through it carries your agent's identity document and a fresh signature over that specific request, made with your domain's control key.
The signature is the whole point. The document is public — anyone can download it from its verify_url, and attaching it proves nothing on its own. That is why AGT-9303 §7.3 requires a signature computed over this request, valid for sixty seconds, checked against the key recorded on L1. A copied document opens nothing.
import { loadSigningKey } from 'bindagt';
// Reads BINDAGT_KEY_FILE and BINDAGT_KEY_PASSWORD.
// The key stays in this process — only signatures leave it.
const { key, keyType } = loadSigningKey();
const { fetch } = await presentAs('agt://acme.com/support-bot', {
signer: key,
keyType,
});
await fetch('https://partner.example.com/agent', { method: 'POST', body });
Always forward keyType. It defaults to 1 (P-256), but a key file created by the dashboard or by bindagt key generate is 0 (secp256k1). loadSigningKey() returns the correct value — pass it through, or every signature you send will be rejected.
To keep the key in a KMS or an HSM, pass a signing function as signer instead; the library then never holds the key at all. There is also an unsigned: true escape hatch that attaches the document with no signature, for migrating an existing integration — it identifies the agent, proves nothing about the caller, may be rejected by a conforming verifier, and will be removed. Do not build on it.
Verify who's calling you
Register the guardrail on your agent, and pass the inbound header into run()'s context from your own HTTP handler — the Agents SDK never sees raw requests, so that one line of wiring is yours.
import { verifyIdentityGuardrail } from '@bindagt/openai';
const agent = new Agent({
name: 'Support Bot',
inputGuardrails: [verifyIdentityGuardrail()],
});
// in your HTTP handler:
const result = await run(agent, input, {
context: { agtIdentityHeader: req.headers['agt-identity'] },
});
The guardrail checks the signature by default (requirePossession is true): a caller that presents a valid document without proving it holds the key is rejected. Pass the request itself in run()'s context alongside the header so the signature can be checked against the method, path and body it was made over.
required defaults to false. A caller with no AGT-Identity header at all passes through as anonymous, with verified: false — the same way most of the web treats a missing optional auth header. Set required: true to refuse unidentified callers outright.
Verification is always live against the registry — a cached or replayed document can't outrun a suspension, because the current registry state decides, not the document's own claims. Agents on other frameworks can implement the same flow directly from the AGT-9303 standard.
AGT-9303 standard
AGT-9303 is the specification behind Bindagt. We wrote it and published it in full: it defines how agents are named, recorded, resolved and transferred. It is free to read and free to implement, and you can build your own client against the same records — including one that competes with ours. An identity you could only check through us would not be worth much.
- Naming — the
agt://scheme and the root/agent hierarchy. - Anchoring — how identity records are written immutably.
- Resolution — how a client resolves and verifies an identifier.
- Transfer — how ownership of an identity moves between parties.
SDK reference
The bindagt package exposes the verification helpers and a CLI for registration.
Resolves an agt:// identifier through the API and returns a VerifyResult with its status and metadata. No authentication required.
Reads the registry directly over public RPC and returns a VerifyResult. Independent of Bindagt's servers, at $0.
CLI command that registers a domain and records your first agent, walking you through the DNS challenge. Needs an interactive terminal: it asks for the password that encrypts your signing key.