POST /v1/register
Agent self-registration. No authentication. The agent sends its own RSA public key. Nothing takes effect until the owner approves with a passkey.
With a pairing code (paste-prompt onboarding)
POST /v1/register HTTP/1.1
Host: api.agentvalet.ai
Content-Type: application/json
{
"pairing_code": "pc_7Kq2mX9pLw4Zr8Tn3Vb6Yc",
"agent_name": "Instinct",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\n…\n-----END PUBLIC KEY-----"
}The pairing code comes from a prompt the owner generated in AgentValet. It identifies the owner and
fixes the agent’s name and any starting grants, so owner_id and requested_scopes are not sent.
public_key_pem is required: an RSA key of at least 2048 bits, SPKI PEM.
Without a pairing code (unsolicited)
{ "owner_id": "<owner uuid>", "agent_name": "my-agent", "requested_scopes": [], "public_key_pem": "…" }Flagged as unsolicited on the owner’s approval page, and limited to 5 per owner per hour.
Response: 202
{
"data": {
"status": "pending_approval",
"registration_token": "…",
"poll_url": "/v1/register/status/…",
"approve_url": "https://app.agentvalet.ai/m/registrations/…#v=…",
"key_fingerprint": "3F9A-11C0-8B2E-7D41",
"expires_in": 86400,
"pairing_matched": true,
"keypair_source": "client"
},
"_meta": { … }
}approve_url: send it to the user. It opens the approval page; approving needs their passkey.key_fingerprint: send it to the user too. The approval page shows the same value, so they can confirm the registration is yours.poll_url:GETit onhttps://api.agentvalet.aiuntilstatusisapproved,rejectedorexpired. Onapprovedit returnsagent_idandowner_id.
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_public_key | Not an RSA ≥ 2048-bit SPKI public key (or a private key was sent) |
| 400 | public_key_required | pairing_code sent without public_key_pem |
| 400 | invalid_pairing_code | Malformed code |
| 404 | pairing_not_found | Unknown code |
| 409 | pairing_used | The code was already used. The owner is notified |
| 410 | pairing_expired | Ask the user to generate a new prompt |
| 429 | too_many_unsolicited_registrations | Use a pairing code |
After approval
Authenticate every request with Authorization: Bearer <JWT>, a fresh RS256 JWT signed with your
private key, with claims {agent_id, owner_id, iat, exp} and exp = iat + 60. Tokens for assistant
agents that would live longer than 300 seconds are refused with 401 jwt_lifetime_exceeded.
Then call GET /v1/agents/me, GET /v1/agent/permissions (each platform has apiHints) and
POST /v1/actions. For an audit, GET /v1/agents/me/audit-link returns a link for the user.