Sigil Protocoldocs
ExplorerSKILL.md
REST API

Registration API

HTTP endpoints for sponsored agent registration. External agents (with no SDK access) use this flow to obtain a passportId and agent private key — routed through a human principal who signs the on-chain transaction.

INFOAll API endpoints are served by the Next.js app at http://localhost:3000 in development. Deploy the demo/ui package to Vercel or any Node.js host for a public URL.

Base URL

bash
BASE_URL=http://localhost:3000   # development
BASE_URL==https://sigiltwoelves.vercel.app # production

Registration Flow

1Agent POSTs to /register/request — gets requestId + approvalUrl
2Agent shows approvalUrl to the principal (human)
3Principal visits the approve page, connects wallet, signs register() tx
4Agent polls /register/status/:requestId every 5s until approved
5First approved response delivers agentPrivateKey (exactly once)
6Agent stores passportId + agentPrivateKey, begins notarizing

Create Registration Request

POST/api/v1/passport/register/request

Generate a fresh agent keypair, pre-compute the passportId, and create a pending registration with a 24-hour TTL. Returns a requestId and an approvalUrl to present to the principal.

Request Body

ParameterTypeDescription
principalAddressrequiredstring0x + 40 hex chars. The wallet that will own the AgentPassport iNFT.
agentDescriptionrequiredstringFree-text description of the agent (≤ 280 characters).
permissionsrequiredobjectPermission manifest defining what the agent is authorized to do.
permissions.whitelistedContractsstring[]Contract addresses the agent may interact with.
permissions.maxTxValuePerWindowRecord<string, number>Max token value per rolling window. e.g. { 'OG': 0 }
permissions.authorizedApisstring[]External API identifiers. e.g. ['0g.compute']
permissions.allowedTokensstring[]Token symbols the agent may use.
permissions.timeWindowSecondsnumberRolling window duration in seconds.

Example Request

bash
curl -X POST $BASE_URL/api/v1/passport/register/request \
  -H "Content-Type: application/json" \
  -d '{
    "principalAddress": "0xYourWalletAddress",
    "agentDescription": "Risk scoring agent for DeFi protocols",
    "permissions": {
      "whitelistedContracts": [],
      "maxTxValuePerWindow": { "OG": 0 },
      "authorizedApis": ["0g.compute"],
      "allowedTokens": ["OG"],
      "timeWindowSeconds": 3600
    }
  }'

Response

json
{
  "requestId": "a1b2c3d4e5f6...",
  "agentAddress": "0x...",
  "passportId": "0x...",
  "approvalUrl": "http://localhost:3000/approve/a1b2c3d4...",
  "expiresAt": 1746086400000
}

Error Responses

ParameterTypeDescription
400Bad RequestMissing or invalid fields in the request body.
429Too Many RequestsRate limit exceeded: max 5 requests per IP per hour, or max 10 pending per principal.

Poll Registration Status

GET/api/v1/passport/register/status/:requestId

Poll until the principal approves the registration. The first response with status: "approved" includes agentPrivateKey — it is never returned again after that.

Example Request

bash
curl $BASE_URL/api/v1/passport/register/status/a1b2c3d4e5f6...

Response — Pending

json
{
  "status": "pending",
  "requestId": "a1b2c3d4...",
  "agentAddress": "0x...",
  "passportId": "0x...",
  "agentDescription": "Risk scoring agent for DeFi protocols",
  "createdAt": 1746000000000,
  "expiresAt": 1746086400000
}

Response — Approved (first call)

IMPORTANTStore agentPrivateKey immediately. This is the only call that returns it. Subsequent calls omit the key.
json
{
  "status": "approved",
  "requestId": "a1b2c3d4...",
  "passportId": "0x...",
  "agentAddress": "0x...",
  "agentPrivateKey": "0x...",
  "approvalTxHash": "0x..."
}

Response — Approved (subsequent calls)

json
{
  "status": "approved",
  "requestId": "a1b2c3d4...",
  "passportId": "0x...",
  "agentAddress": "0x...",
  "approvalTxHash": "0x..."
}

Polling Pattern

typescript
async function waitForApproval(requestId: string, baseUrl: string) {
  while (true) {
    const res = await fetch(`${baseUrl}/api/v1/passport/register/status/${requestId}`);
    const data = await res.json();

    if (data.status === "approved") {
      if (data.agentPrivateKey) {
        // Store immediately — won't be returned again
        process.env.SIGIL_AGENT_PRIVATE_KEY = data.agentPrivateKey;
        console.log("passportId:", data.passportId);
      }
      return data;
    }

    if (data.error) throw new Error(data.error);

    await new Promise(r => setTimeout(r, 5000)); // poll every 5s
  }
}

Approve Registration

POST/api/v1/passport/approve/:requestId

Called by the /approve/:requestId browser page after the principal submits the SigilRegistry.register() transaction. Not normally called directly by agents.

INFOThe approve endpoint verifies a principalSignature over the message sigil-approve:<requestId>. It must recover to the principalAddress stored in the pending registration. This prevents a third party from marking a request as approved.

Request Body

ParameterTypeDescription
txHashrequiredstringThe register() transaction hash (0x + 64 hex chars).
passportIdrequiredstringThe passportId confirmed by the transaction.
principalSignaturerequiredstringPrincipal's personal_sign over 'sigil-approve:<requestId>'.

Response

json
{ "ok": true, "passportId": "0x..." }

Rate Limits

ParameterTypeDescription
IP rate limit5 / hourMax 5 new registration requests per IP address per hour.
Principal limit10 activeMax 10 pending (unapproved) registrations per principal address at any time.
TTL24 hoursPending registrations expire after 24 hours if not approved. Local development uses a 60-second sweeper; hosted deployments should back the API with durable KV.
NOTEHosted/serverless deployments should set KV_REST_API_URL and KV_REST_API_TOKEN (or the raw Upstash equivalents) so the request, approve, and status routes share durable state across instances. If those vars are unset, the app falls back to an in-memory store for local development only.

Additional Endpoints

GET/SKILL.md

The agent onboarding document. Machine-readable. Any AI agent can fetch and parse this to self-onboard without human guidance.

GET/api/storage/:rootHash

Server-side proxy to 0G Storage. Returns raw bytes for a given content-addressed root hash. Used by the resolver UI to download proof envelopes and encrypted manifests without browser-side 0G SDK dependencies.