API Reference

Complete endpoint documentation.

1

Base URLs

Environments

Environment Base URL
Production https://api.signedbyme.com
Beta https://api.signedbyme.com
All requests must use HTTPS. HTTP requests will be rejected.
2

OIDC Discovery

Standard OpenID Connect discovery endpoints for token validation.

GET /.well-known/openid-configuration

Returns the OpenID Connect discovery document.

Response

{
  "issuer": "https://api.signedbyme.com",
  "authorization_endpoint": "https://api.signedbyme.com/oauth/authorize",
  "token_endpoint": "https://api.signedbyme.com/oauth/token",
  "jwks_uri": "https://api.signedbyme.com/oidc/jwks.json",
  "response_types_supported": ["id_token"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "claims_supported": ["sub", "iss", "aud", "exp", "iat", "nonce"]
}
GET /oidc/jwks.json

Returns the JSON Web Key Set for token signature validation.

Response

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "signedby-2026",
      "use": "sig",
      "alg": "RS256",
      "n": "...",
      "e": "AQAB"
    }
  ]
}
3

Enrollment

Enroll an agent into the Merkle tree during the Genesis flow.

POST /v1/membership/enroll/commit

Commit an agent enrollment. Requires both the enterprise authorization (kind 28200) and human delegation (kind 28250) events.

Request Body

Field Type Description
leaf_commitment required string Hex-encoded leaf commitment (32 bytes)
authorization_event required object Kind 28200 NOSTR event signed by enterprise
delegation_event required object Kind 28250 NOSTR event signed by human

Request Example

{
  "leaf_commitment": "0x1a2b3c4d5e6f...",
  "authorization_event": {
    "kind": 28200,
    "pubkey": "<enterprise_npub_hex>",
    "created_at": 1704067200,
    "tags": [["p", "<agent_npub_hex>"], ["client_id", "acme-corp"]],
    "content": "{\"scopes\":[\"read\",\"write\"]}",
    "id": "<event_id>",
    "sig": "<enterprise_signature>"
  },
  "delegation_event": {
    "kind": 28250,
    "pubkey": "<human_npub_hex>",
    "created_at": 1704067200,
    "tags": [["p", "<agent_npub_hex>"]],
    "content": "{\"agent_npub\":\"npub1...\",\"scopes\":{...},\"expires_at\":\"...\",\"delegation_id\":\"...\"}",
    "id": "<event_id>",
    "sig": "<human_signature>"
  }
}

Response (200 OK)

{
  "enrollment_id": "enr_abc123",
  "status": "committed",
  "tree_id": "tree_acme_members",
  "root": "0x7890abcdef...",
  "leaf_index": 42,
  "witness": {
    "siblings": ["0x...", "0x...", ...],
    "path_bits": [0, 1, 0, 1, ...]
  },
  "message": "Enrollment committed successfully"
}
Save the witness! You'll need siblings and path_bits to generate proofs later. The SDK handles this automatically.
4

Login Verification

Verify a Groth16 proof and receive an OIDC token.

POST /v1/login/verify

Verify an agent's proof and return an OIDC id_token. Server checks that the Merkle root is valid for the given client.

Request Body

Field Type Description
proof required string Groth16 proof (hex-encoded)
public_outputs required object Circuit public outputs
public_outputs.merkle_root required string Merkle root (hex)
public_outputs.npub required string Agent's npub (bech32)
client_id required string Enterprise client ID
nonce optional string Nonce for replay protection

Request Example

{
  "proof": "0xabcdef123456...",
  "public_outputs": {
    "merkle_root": "0x7890abcdef...",
    "npub": "npub1abc..."
  },
  "client_id": "acme-corp",
  "nonce": "random_nonce_string"
}

Response (200 OK)

{
  "ok": true,
  "id_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "sub": "npub1abc..."
}

ID Token Claims

{
  "iss": "https://api.signedbyme.com",
  "aud": "acme-corp",
  "sub": "npub1abc...",
  "iat": 1704067200,
  "exp": 1704070800,
  "nonce": "random_nonce_string",
  "amr": ["did_sig", "groth16_proof", "ln_payment"],
  "membership_verified": true
}
Server checks: The Merkle root must be in the last 30 valid roots for this client_id. This allows for tree updates without immediately invalidating existing proofs.
5

Error Codes

All errors return a JSON object with error and message fields.

HTTP Error Code Description
400 invalid_request Missing or malformed request parameters
400 invalid_proof Groth16 proof verification failed
400 invalid_signature NOSTR event signature verification failed
400 root_expired Merkle root not in last 30 valid roots
401 invalid_client Unknown or unauthorized client_id
403 enrollment_denied Enterprise did not authorize this enrollment
404 tree_not_found No Merkle tree exists for this client
409 already_enrolled This leaf commitment is already in the tree
429 rate_limited Too many requests, slow down
500 internal_error Server error, retry later

Error Response Example

{
  "error": "root_expired",
  "message": "Merkle root 0x7890... is not in the last 30 valid roots for client acme-corp"
}
6

Rate Limits

Rate limits protect the service from abuse.

Default Limits

Endpoint Limit Window
/v1/login/verify 100 requests per minute per IP
/v1/membership/enroll/commit 10 requests per minute per IP
OIDC discovery 1000 requests per minute per IP

Rate Limit Headers

Responses include these headers:

  • X-RateLimit-Limit — Maximum requests allowed
  • X-RateLimit-Remaining — Requests remaining in window
  • X-RateLimit-Reset — Unix timestamp when limit resets
When rate limited (429): Wait until X-RateLimit-Reset before retrying. Implement exponential backoff in your client.