Enforcer v3 docs / Enforcer Recipes
How to
Recipes
Short, copyable answers to the things you will do in the first week.
Gate a page on KYC
This is the core mechanic. The route is protected by group membership. A new user is not in the group, so the action is forbidden. When the KYC module reports a pass, you add the account to the verified group and the same route now allows them.
# on KYC pass, add the account to the gating group curl -X POST "$ENFORCER_BASE_URL/api/v1/enforcer/groups/$GROUP_ID/members" \ -H "X-API-Key: $API_KEY" \ -d '{ "account_id": "$ACCOUNT_ID" }' # to revoke access later, remove them curl -X DELETE "$ENFORCER_BASE_URL/api/v1/enforcer/groups/$GROUP_ID/members/$ACCOUNT_ID" \ -H "X-API-Key: $API_KEY"
The route itself does not change. You are only changing who is in the group.
Add a login method
Enforcer supports passkey, email OTP, phone OTP over SMS, Google, SIWE, and Privy. The provider field on login and register selects the method. Email OTP login looks like this:
curl -X POST "$ENFORCER_BASE_URL/api/v1/enforcer/auth/login" \ -d '{ "provider": "email_otp", "email": "user@acme.com", "otp": "123456", "tenant_code": "$TENANT_CODE" }'
For Google or Privy you pass the provider token in the token field instead of an OTP. Set which method your tenant accepts with the dedicated auth-provider call:
curl -X PUT "$ENFORCER_BASE_URL/api/v1/enforcer/tenants/$TENANT_ID/auth-provider" \ -H "Authorization: Bearer $ADMIN_JWT" \ -H "Content-Type: application/json" \ -d '{ "provider": "email_otp" }'
Confirm the exact passkey and SIWE begin and finish routes against the live spec for your build.
Invite teammates
Create an invite for your tenant, then the invitee accepts it to join.
# create an invite (tenant admin) curl -X POST "$ENFORCER_BASE_URL/api/v1/enforcer/tenants/$TENANT_ID/invites" \ -H "Authorization: Bearer $ADMIN_JWT" \ -d '{ "email": "teammate@acme.com" }' # invitee accepts curl -X POST "$ENFORCER_BASE_URL/api/v1/enforcer/auth/invites/accept" \ -H "Authorization: Bearer $USER_JWT" \ -d '{ "code": "$INVITE_CODE" }'
To set what a teammate can do, assign them a role with PUT /accounts/{id}/role. List the available roles with GET /roles.
Theme your app
Set the tenant name, logo, and theme with a single patch.
curl -X PATCH "$ENFORCER_BASE_URL/api/v1/enforcer/tenants/$TENANT_ID" \ -H "Authorization: Bearer $ADMIN_JWT" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Pay", "logo_url": "https://acme.com/logo.png", "theme": { "primary": "#6ce992" } }'
Switch a user between tenants
Because the person sits above per tenant users, one human can hold memberships in several tenants. List them, then switch. A switch returns a token scoped to the new tenant.
# list this person's tenant memberships curl "$ENFORCER_BASE_URL/api/v1/enforcer/auth/tenants" \ -H "Authorization: Bearer $USER_JWT" # switch into another tenant curl -X POST "$ENFORCER_BASE_URL/api/v1/enforcer/auth/tenant/switch" \ -H "Authorization: Bearer $USER_JWT" \ -d '{ "tenant_id": "$OTHER_TENANT_ID" }'
To join a tenant the person is not yet a member of, use POST /auth/tenant/join with a tenant_code.