Users
Users are managed via Keycloak. Assign users to tenants with per-environment roles to control access. List users, assign to tenants, or remove access.
What are users
Users represent people who can access Payment Reconciler. User identity is managed by Keycloak (email, password, SSO). Payment Reconciler stores a local user record linked to Keycloak and supports tenant assignment—granting a user access to specific tenants and environments with a role (admin or viewer).
Access control works as follows: a user must be assigned to a tenant (and optionally a specific environment) to access that tenant's data. The X-Tenant-Id and X-Environment headers in API requests determine which tenant/environment the user is acting in.
Keycloak integration
Users are created or synced from Keycloak. When you create a user via POST /users, the service provisions Keycloak and the local database. By default an invite email is sent with a one-time link; the user sets their password via POST /auth/invite/accept before signing in. Passwords are not returned in API responses in production.
Set sendInvite: false on create to skip the email (development only may return a generated password when invites are disabled).
Invite and assignment emails
| Event | Email template | User action |
|---|---|---|
New user (POST /users) | user.invited | Accept link → set password |
Resend (POST /users/:id/resend-invite) | user.invited | New accept link |
Assign existing user (POST /tenants/:tenantId/users) | user.tenant_assigned | Sign in with existing credentials |
Public endpoints (no auth): POST /auth/invite/verify, POST /auth/invite/accept.
See Tenant Branding for org display name and logo. GET /users/me includes memberships[].tenant.branding.
Invite status vs user status
status is the account-level state (ACTIVE, SUSPENDED, INACTIVE). New users are currently created as ACTIVE, even before they accept an invite.
To let the frontend track onboarding, user responses include an invite summary derived from invite records:
| Field | Meaning |
|---|---|
invite.inviteStatus | NOT_SENT, PENDING, ACCEPTED, or EXPIRED for the latest invite |
invite.lastInvitedAt | Timestamp of the latest invite/resend |
invite.inviteAcceptedAt | Timestamp when an invite was accepted, if any |
invite.inviteExpiresAt | Expiry timestamp for the latest invite |
invite.inviteCount | Total number of invites/resends created for the user |
invite.lastInviteType | NEW_USER, RESEND, or TENANT_ASSIGNED |
Use invite.inviteStatus to show “Invite pending” or “Accepted” in user-management UI. Use status only for account availability/admin deactivation.
Tenant assignment
To give a user access to a tenant:
- Assign —
POST /tenants/:tenantId/userswithuserId,environment, androle - List tenant users —
GET /tenants/:tenantId/usersto see who has access - Remove —
DELETE /tenants/:tenantId/users/:userIdto revoke access
Assignment can be per-environment (e.g. user has access only to production) or across environments depending on your setup.
Roles
| Role | Access |
|---|---|
| admin | Full access to the tenant environment—create, update, delete resources |
| viewer | Read-only access—list and retrieve, no create/update/delete |
Roles are enforced per tenant and environment. A user can be admin for one tenant and viewer for another.
User lifecycle
- Create — Provision a new user (Keycloak-backed)
- List — List all users (filter by tenant if needed)
- Update — Update display name, status
- Deactivate —
DELETE /users/:iddeactivates the user (soft delete; they lose access)
API Reference
For user creation, tenant assignment parameters, and request/response samples, see Users in the API Reference.