Invite User to Tenant
Implement OAM::IAM::0006::0004.UC
from Identity and Access Management Behaviors.
Constraints
Section titled “Constraints”- Any user of a tenant can send an invitation.
- The system sends the invitation email automatically when an invitation is created, refreshed, or reopened.
- An invitation inbox is out of scope. Invitees manage invitations in their email inbox.
- Batch operations (creation, management) of invitations is out-of-scope.
- Email can be disabled per deployment. In that mode, a no-op sender reports success so invitation workflows can run without contacting the mail server.
Requirements
Section titled “Requirements”For any tenant user
Section titled “For any tenant user”- Invite a user (identified by email) that does not have an invitation yet or only has archived invitations to join the tenant. The caller may supply custom message parameters for the configured template.
- View all invitations sorted by creation date (descending), filterable by status (PENDING, ACCEPTED, EXPIRED, REJECTED, CANCELLED, ARCHIVED, PENDING_FAILED) with pagination.
- Cancel an invitation in
PENDINGstatus. - Reopen an invitation in
CANCELLED,EXPIRED, orREJECTEDstatus, returning it toPENDING. - Archive an invitation in
PENDING,ACCEPTED,CANCELLED,EXPIRED, orREJECTED, moving it toARCHIVED. - Refresh an invitation in
PENDINGstatus, updating itsinvitationDateto the current date and time and itsexpirationDateto the current date and time plus the configured expiration interval. - Retry a failed delivery by moving a
PENDING_FAILEDinvitation toPENDING.
For the invitee
Section titled “For the invitee”- Accept the invitation (joining the tenant).
- Reject the invitation.
For the system
Section titled “For the system”- Provide the invitation as a link encoding the invitation identifier and (for convenience) the invitee’s email.
- Render and send an email whenever an invitation enters
PENDING, including creation, refresh, reopen, and retry. - Protect the system-owned
invitation_template parameters from caller overrides. - If rendering, message construction, or sending fails, transition the invitation to
PENDING_FAILED; persist the sender outcome inmessageStatuswhen one is available. - Collect metrics for template renders and successful and failed email sends.
- Validate the invitation:
- Exists
- Is in
PENDINGstatus - Is addressed to the logged-in user
Email enablement
Section titled “Email enablement”Accounts selects its sender at startup. It constructs the configured System Email sender only when features.email=true
and an email {} configuration is present; otherwise it uses NoOpEmail.
With NoOpEmail, the service follows the same render-and-send control flow but receives a synthetic successful outcome
with message ID noop. This keeps the invitation in PENDING without contacting Postmark.
Information Model
Section titled “Information Model”General Information Contents
Section titled “General Information Contents”All entities will include the following information:
| Field Name | Type | Description | Notes |
|---|---|---|---|
id | UUID | A unique identifier for the entity in the system | Generated by the system. Not editable |
rId | UUID | A unique identifier for a particular version of the entity | Not editable |
createdBy | Text | The identification of the user that created the entity | Not Editable |
createdAt | TimeCoordinates | The time when the entity was created, specifying when it was created in the real world and when it was recorded by the system. | |
author | Text | The identification of the users that made the latest change (version) of the entity. | |
asOf | TimeCoordinates | The time when the latest change was made (effective and recorded). |
In addition, Invitations belong to a tenant, so they will also have:
| Field Name | Type | Description | Notes |
|---|---|---|---|
tenantId | UUID | The identification of the tenant that owns this entity. |
Entities
Section titled “Entities”Invitation
Section titled “Invitation”| Field | Type | Default | Editable | Description |
|---|---|---|---|---|
invitationDate | Date | Created at | No | Date invitation was created |
expirationDate | Date | invitationDate + configurable interval | No | Expiry date |
status | Enum | PENDING | No | Current lifecycle status |
invitee | String | Blank | Yes | Email of invited user |
inviterId | UUID | Current user id | No | ID of inviting user |
tenantId | UUID | Current tenant id | No | Tenant being invited to |
messageParameters | Map<String, String> | Empty map | No | Caller-supplied values used when rendering the invitation email. Keys beginning with invitation_ are removed on creation. |
messageStatus | String | Empty string | No | Diagnostic sender outcome for a failed delivery, when available. Cleared before a new transition attempt. |
Invitation Lifecycle
Section titled “Invitation Lifecycle”The state diagram annotates those states and transitions that are triggered by the invitee or the system events. All other transitions (e.g. cancel, archive) are triggered by a user in the inviting tenant.
These operations (refresh, cancel, …) are implemented as update of the status field on the invitation entity, as described by the transition diagram below.
Sequence Overview
Section titled “Sequence Overview”- Inviter creates an invitation via Company Settings > Users, optionally supplying template parameters.
- The system registers the invitation as
PENDING, generates its URL and protected template parameters, renders the configured system template, and sends the email. - If delivery fails, the system records a new
PENDING_FAILEDversion. A tenant user can retry it by requestingPENDING; the retry refreshes the invitation and expiration timestamps and sends again. - Invitee opens the link from the email, then signs in or creates an account if needed.
- System validates the invitation.
- On accept:
- invitation transitions to
ACCEPTED. - a new
AgentForis created linking the invitee’s UserAccount to the tenant; - the invitee’s role in the tenant is set to
USER; - invitee’s active tenant is set to the new tenant.
- invitation transitions to
- On reject:
- invitation transitions to
REJECTED.
- invitation transitions to
Every transition to PENDING attempts to send an email. This includes a refresh (PENDING → PENDING), a reopen from
CANCELLED, EXPIRED, or REJECTED, and a retry from PENDING_FAILED. The existing no-op interval still suppresses a
refresh requested too soon; because no state transition occurs, no email is sent.
Activities
Section titled “Activities”Copyright: © Arda Systems 2025-2026, All rights reserved