Identity API
The Identity API enables operators to verify their identity through external providers, creating verified claims that can be attached to agent passports. STACK implements a three-layer trust model where identity verification unlocks higher trust levels and broader access across the platform.
All endpoints require an Authorization: Bearer sk_live_... header with a valid operator API key or team member API key, except the Stripe webhook endpoint.
Three-Layer Trust Model
STACK uses a graduated trust model where each layer builds on the previous one:
Layer 1 — Humanity
Proves that a verified human is behind the operator account. Produces a verified_human claim. This claim is safe to embed directly in passport JWTs (no PII). Required for most skill invocations and cross-operator interactions.
Layer 2 — Identity
Proves the operator's real-world identity through a government ID or financial institution. Produces a verified_identity claim. PII is encrypted at rest and never stored in the JWT — only a claim_ref is embedded, which is resolved server-side during verification. Required for high-value transactions and regulated workflows.
Layer 3 — Delegation
Allows verified operators to explicitly delegate authority to agents for specific scopes (e.g., tax:file, tax:read). The delegated scopes are embedded in the passport JWT. This is a separate consent step from identity verification.
List Identity Providers
GET /v1/identity/providers
Retrieve the list of available identity verification providers with their supported trust layers, assurance levels, and claim types.
Request Example
curl https://api.getstack.run/v1/identity/providers \
-H "Authorization: Bearer sk_live_op_abc123"Response — 200 OK
Each provider object follows the IdentityProvider schema:
[
{
"id": "idp_abc123",
"name": "BankID Sweden",
"provider_key": "bankid_se",
"supported_layers": ["humanity", "identity"],
"claim_types": ["verified_human", "verified_identity"],
"assurance_level": "high",
"active": true
},
{
"id": "idp_def456",
"name": "Stripe Identity",
"provider_key": "stripe_identity",
"supported_layers": ["humanity", "identity"],
"claim_types": ["verified_human", "verified_identity"],
"assurance_level": "high",
"active": true
},
{
"id": "idp_ghi789",
"name": "Login.gov",
"provider_key": "login_gov",
"supported_layers": ["humanity", "identity"],
"claim_types": ["verified_human", "verified_identity"],
"assurance_level": "substantial",
"active": true
}
]Assurance Levels
- high — Government-issued ID or regulated financial institution verification. Suitable for KYC/AML.
- substantial — Strong verification through trusted third party. Suitable for most commercial use cases.
- low — Basic verification. May not meet requirements for L2 identity claims.
Initiate Verification
POST /v1/identity/verify/initiate
Start an identity verification flow with the specified provider. Returns a session reference and redirect URL or client secret depending on the provider type.
Request Body
{
"provider_key": "stripe_identity",
"requested_claims": ["verified_human", "verified_identity"],
"return_url": "https://getstack.run/identity/callback"
}- provider_key (string, required) — Provider key from the providers list (e.g., bankid_se, stripe_identity, login_gov, id_me, plaid).
- requested_claims (string[], required) — Array of claim types to request. At least one required.
- return_url (string, optional) — URL to redirect to after verification completes.
Request Example
curl -X POST https://api.getstack.run/v1/identity/verify/initiate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_op_abc123" \
-d '{
"provider_key": "stripe_identity",
"requested_claims": ["verified_human"],
"return_url": "https://getstack.run/identity/callback"
}'Response — 201 Created
The response varies by provider but always includes a session reference for completing the flow.
Error Responses
- 400 Bad Request — Invalid provider_key or empty requested_claims.
- 401 Unauthorized — Missing or invalid Authorization header.
- 409 Conflict — An active verification session already exists for this provider.
List Pending Sessions
GET /v1/identity/verify/sessions
Retrieve pending verification sessions for your operator account. Useful for checking the status of in-progress verifications.
Request Example
curl https://api.getstack.run/v1/identity/verify/sessions \
-H "Authorization: Bearer sk_live_op_abc123"Response — 200 OK
[
{
"session_id": "vs_abc123",
"provider_key": "stripe_identity",
"session_ref": "vs_1_abc123",
"status": "pending",
"created_at": "2026-04-15T10:30:00.000Z",
"expires_at": "2026-04-15T11:30:00.000Z"
}
]Sync Provider Sessions
POST /v1/identity/verify/sync
Sync with an external provider to auto-complete any verified sessions that STACK has not yet processed. This queries the provider directly (e.g., Stripe) to check if any pending sessions have been completed on the provider's side.
Request Body
{
"provider_key": "stripe_identity"
}Complete Verification
POST /v1/identity/verify/complete
Complete a pending verification by submitting the provider's session reference. This endpoint takes the provider_key and session_ref — there is no verification ID in the URL path.
Request Body
{
"provider_key": "stripe_identity",
"session_ref": "vs_1_abc123"
}- provider_key (string, required) — The same provider key used in the initiation step.
- session_ref (string, required) — The session reference from the provider.
Request Example
curl -X POST https://api.getstack.run/v1/identity/verify/complete \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_op_abc123" \
-d '{
"provider_key": "stripe_identity",
"session_ref": "vs_1_abc123"
}'Error Responses
- 400 Bad Request — Invalid provider_key or session_ref.
- 401 Unauthorized — Missing or invalid Authorization header.
- 404 Not Found — No pending session found for this provider and session reference.
- 422 Unprocessable Entity — Provider rejected the verification.
Inline Token Verification
POST /v1/identity/verify/token
For providers that use an inline widget (e.g., Turnstile), the frontend collects a token and POSTs it here to complete verification. Requires provider_key,session_ref, and token in the body.
Request Body
{
"provider_key": "turnstile",
"session_ref": "sess_ref_abc",
"token": "0.abc123..."
}Grant Delegation
POST /v1/identity/delegate
Grant a Layer 3 delegation claim by specifying the scopes you authorize. This is a separate consent step — the operator explicitly declares which actions their agents are authorized to perform on their behalf.
Request Body
{
"delegated_scopes": ["tax:file", "tax:read", "bank:transfer"]
}- delegated_scopes (string[], required) — Array of scope strings to delegate. At least one required.
Request Example
curl -X POST https://api.getstack.run/v1/identity/delegate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_op_abc123" \
-d '{
"delegated_scopes": ["tax:file", "tax:read"]
}'Response — 201 Created
Returns the created delegation claim record.
List Verified Claims
GET /v1/identity/claims
Retrieve all verified identity claims for the authenticated operator. Claims are the output of successful identity verifications and can be selectively attached to passports via the identity_claim_ids field when issuing.
Request Example
curl https://api.getstack.run/v1/identity/claims \
-H "Authorization: Bearer sk_live_op_abc123"Revoke a Claim
DELETE /v1/identity/claims/:id
Revoke a specific identity claim. This also triggers smart revocation of any active passports that carry this claim — passports without the claim are unaffected.
Request Example
curl -X DELETE https://api.getstack.run/v1/identity/claims/clm_9xm3kR7wL2 \
-H "Authorization: Bearer sk_live_op_abc123"Response — 200 OK
{
"success": true
}Revoking a claim invalidates all active passports that carry it. This is a cascading action — make sure you understand which passports will be affected before revoking.
Service Identity Requirements
You can set identity requirements on services, specifying which trust layer, claim type, and assurance level is needed before an agent can access the service.
Get Requirements
GET /v1/services/:id/requirements
curl https://api.getstack.run/v1/services/svc_123/requirements \
-H "Authorization: Bearer sk_live_op_abc123"Set Requirement
POST /v1/services/:id/requirements
{
"layer": "humanity",
"requires_claim": "verified_human",
"minimum_assurance": "substantial",
"accepted_providers": [],
"requires_pii": false
}- layer (string, required) — Trust layer: "humanity", "identity", or "delegation".
- requires_claim (string, required) — The claim type required (e.g., "verified_human", "verified_identity").
- minimum_assurance (string, required) — Minimum assurance level: "low", "substantial", or "high".
- accepted_providers (string[], optional) — Restrict to specific provider keys. Empty array means any provider accepted.
- required_scopes (string[], optional) — For Layer 3 delegation matching.
- requires_pii (boolean, optional) — Must be true for Layer 2 (identity) requirements. Default: false.
- lawful_basis (string, optional) — GDPR lawful basis. Required when requires_pii is true.
Layer 2 (identity) requirements must set requires_pii: true and provide a lawful_basis. Attempting to create a Layer 2 requirement without these fields returns a GDPR_VIOLATION error.
Stripe Identity Webhook
POST /v1/identity/webhooks/stripe
Webhook endpoint for Stripe Identity. Stripe fires an identity.verification_session.verified event when a user completes verification. This endpoint auto-completes the STACK verification flow without requiring client-side state or redirect. The webhook signature is verified using the stripe-signature header.
This endpoint is not authenticated with STACK API keys. It uses Stripe webhook signature verification instead. Configure the webhook URL in your Stripe dashboard as https://api.getstack.run/v1/identity/webhooks/stripe.
PII Handling and GDPR
Identity verification inherently involves personally identifiable information. STACK handles PII with strict security and compliance controls:
- PII is encrypted at rest using AWS KMS envelope encryption.
- PII is never included in passport JWTs. Only a claim_ref is embedded.
- Layer 2 identity requirements must declare requires_pii: true and a lawful_basis.
- All PII access is audit-logged with the same hash-chained, append-only audit trail.
- Layer 1 (humanity) claims carry no PII and are safe to embed directly in JWTs.
- Layer 3 (delegation) claims carry delegated_scopes but no PII.
Provider Details
BankID Sweden (bankid_se)
- Layers: humanity, identity
- Assurance: high (government-regulated)
- Coverage: Swedish residents with BankID
Stripe Identity (stripe_identity)
- Layers: humanity, identity
- Assurance: high (document + selfie verification)
- Coverage: Global (200+ countries)
- Supports webhook auto-completion
Login.gov (login_gov)
- Layers: humanity, identity
- Assurance: substantial (IAL1) to high (IAL2)
- Coverage: US residents
ID.me (id_me)
- Layers: humanity, identity
- Assurance: substantial (IAL1) to high (IAL2)
- Coverage: US residents, veterans, military
Plaid (plaid)
- Layers: humanity, identity
- Assurance: high (financial institution verification)
- Coverage: US, Canada, UK, EU