Identity-first onboarding for VibeBase agents and gateway services

Agent Quickstart

Use this guide when you want to provision VibeBase identity and service access for agents. The flow is identity-first, then gateway-based for services like email.

🔎 Discovery

Agents should start at https://gateway.vibebase.app. For automated discovery, use https://vibebase.app/api or https://vibebase.app/.well-known/agent.json.

👥 Human Signup vs Agent Onboarding

Humans sign up in the console. Agents should not use the web signup flow — they should onboard via identity and then use the gateway.

👤 Humans: use the Console

If you're a human user, create your account in the console first: console sign up. This guide is for agent self-onboarding via API.

1. Create an Agent Identity

Agents self-create using an Ed25519 public key. This creates an orphan agent.

curl -sX POST https://identity.vibebase.app/v1/agent/init \\
  -H "content-type: application/json" \\
  -d '{
    "publicKey": "83a54e...a2d",
    "name": "bullseye",
    "metadata": {
      "notifications": {
        "claimedWebhookUrl": "https://agent.example.com/webhooks/claimed"
      }
    }
  }' | jq

Response shape:

{
  "success": true,
  "data": {
    "id": "agent-id",
    "publicKey": "83a54e...a2d",
    "tier": "orphan",
    "name": "bullseye",
    "claimUrl": "https://console.vibebase.app/claim/<token>",
    "claimUrlExpiresAt": "2026-05-02T12:34:56.000Z",
    "claimNotificationSubscription": {
      "id": "sub_...",
      "callbackUrl": "https://agent.example.com/webhooks/claimed",
      "eventTypes": ["agent_claimed"]
    }
  }
}

If metadata.notifications.claimedWebhookUrl is provided, VibeBase automatically subscribes that URL to agent_claimed events and returns claimNotificationSubscription in the init response. The response also includes a one-time claimUrl for human handoff.

Optional: Regenerate Claim URL

Agents can request a fresh one-time claim URL (24h default TTL) using their agent JWT.

curl -sX POST https://identity.vibebase.app/v1/claim/link \\
  -H "content-type: application/json" \\
  -H "authorization: Bearer $AGENT_JWT" \\
  -d '{
    "agentId": "agent-id",
    "expiresInMinutes": 1440
  }' | jq

Response shape:

{
  "success": true,
  "data": {
    "claimUrl": "https://console.vibebase.app/claim/<token>",
    "expiresAt": "2026-05-02T12:34:56.000Z"
  }
}

2. Claim the Agent (Human)

The agent signs the claim challenge and a human submits it.

# get challenge
curl -sX POST https://identity.vibebase.app/v1/challenge \\
  -H "content-type: application/json" \\
  -d '{
    "action": "claim",
    "agentId": "agent-id"
  }' | jq

# submit claim
curl -sX POST https://identity.vibebase.app/v1/claim \\
  -H "content-type: application/json" \\
  -d '{
    "agentId": "agent-id",
    "humanId": "clerk-user-id",
    "signature": "hex...",
    "challenge": "vibebase:claim:..."
  }' | jq

Challenge response shape:

{
  "success": true,
  "data": {
    "challenge": "vibebase:claim:agent-id:timestamp:nonce",
    "expiresAt": "2026-05-01T12:34:56.000Z"
  }
}

Claim response shape:

{
  "success": true,
  "data": {
    "id": "agent-id",
    "tier": "claimed",
    "claimedBy": "clerk-user-id"
  }
}

3. Exchange for Identity JWT

The agent signs the token challenge and exchanges it for a JWT.

# get challenge
curl -sX POST https://identity.vibebase.app/v1/challenge \\
  -H "content-type: application/json" \\
  -d '{
    "action": "token",
    "agentId": "agent-id"
  }' | jq

# exchange for JWT
curl -sX POST https://identity.vibebase.app/v1/token \\
  -H "content-type: application/json" \\
  -d '{
    "agentId": "agent-id",
    "signature": "hex...",
    "challenge": "vibebase:token:..."
  }' | jq

Challenge response shape:

{
  "success": true,
  "data": {
    "challenge": "vibebase:token:agent-id:timestamp:nonce",
    "expiresAt": "2026-05-01T12:34:56.000Z"
  }
}

Token response shape:

{
  "success": true,
  "data": {
    "token": "eyJhbGciOi...",
    "expiresAt": "2026-05-02T12:34:56.000Z"
  }
}

4. Request Gateway Service Tokens

Use the identity JWT to request service tokens from the gateway. This is the canonical entrypoint for agent service access.

# get gateway challenge
curl -sX POST https://gateway.vibebase.app/v1/challenge \\
  -H "content-type: application/json" \\
  -d '{
    "action": "token",
    "agentId": "agent-id"
  }' | jq

# request scoped service token
curl -sX POST https://gateway.vibebase.app/v1/token \\
  -H "content-type: application/json" \\
  -H "authorization: Bearer $AGENT_JWT" \\
  -d '{
    "service": "email",
    "action": "send",
    "scope": ["send"],
    "challenge": "gateway:token:agent-id:timestamp:nonce",
    "signature": "hex..."
  }' | jq

Gateway challenge response shape:

{
  "success": true,
  "data": {
    "challenge": "gateway:token:agent-id:timestamp:nonce",
    "expiresAt": "2026-05-01T12:34:56.000Z"
  }
}

Gateway token response shape:

{
  "success": true,
  "data": {
    "serviceToken": "vb_email_agent_...",
    "endpoint": "https://email.vibebase.app",
    "expiresIn": 3600,
    "permissions": ["send"]
  }
}

5. Testing Your Integration

The full SAL smoke test is the reference end-to-end integration sample for envelope handling and full identity flow checks.

# from repo root
bun sal-smoke-test.ts

Full source is documented in the SAL protocol page: /docs/sal-protocol#testing-your-integration.

Note: claim submission is intentionally skipped in smoke tests because claim requires a real signed-in console user.

Notes

  • Orphans (email trial): orphan agents can send email with a trial cap of 10 lifetime sends.
  • Orphans (email constraints): plain-text only, no attachments, max 3 unique recipients before claim.
  • Address stability: orphan and claimed use the same address format: agent_{id}@mail.vibebase.app.
  • Claim notification: optional claimed webhook is pushed through the identity event delivery pipeline.
  • Challenges: challenges expire after ~5 minutes.
  • Gateway: service tokens are short-lived and scoped.