Skip to main content

Invitations API

Base URL: /api/invitations

The Invitations API manages team member invitations with secure token handling, multi-tenant support, and plan limit enforcement.


Security Features

  • Token Hashing: Invitation tokens stored as SHA-256 hashes (never plain text)
  • Token Expiration: 7-day validity period
  • Single Use: Tokens invalidated after acceptance
  • Plan Enforcement: User limits checked before invitation creation

POST /api/invitations

Send an invitation to join the organization.

Authentication: Required
Authorization: Admin role only

Request Body

{
"email": "newuser@example.com",
"role": "developer"
}
FieldTypeRequiredDescription
emailstringYesValid email address
rolestringYesOne of: admin, developer, viewer

Response (201 Created)

{
"success": true,
"message": "Invitation sent. User will create an account.",
"invitation": {
"id": "507f1f77bcf86cd799439011",
"email": "newuser@example.com",
"role": "developer",
"expiresAt": "2026-02-16T10:00:00.000Z",
"userExists": false,
"actionType": "signup"
}
}

Response Fields

FieldDescription
userExiststrue if user already has an account (in any org)
actionTypesignup (new user) or join (existing user)

Error Responses

StatusErrorDescription
400Missing required fieldsEmail or role not provided
400Invalid email formatEmail doesn't match pattern
400Invalid roleRole not admin/developer/viewer
403ForbiddenUser is not an admin
403User limit reachedPlan's max users exceeded
404Organization not foundOrganization doesn't exist
409User already in organizationEmail already a member
409Invitation already sentPending invitation exists
500Failed to send invitationInternal server error

Email Notification

An email is sent to the invitee containing:

  • Organization name
  • Inviter's name
  • Assigned role
  • Invitation link with token
  • Expiration date (7 days)

GET /api/invitations

List pending invitations for the organization.

Authentication: Required
Authorization: Admin role only

Response (200 OK)

{
"success": true,
"invitations": [
{
"id": "507f1f77bcf86cd799439011",
"email": "pending@example.com",
"role": "developer",
"status": "pending",
"invitedBy": "507f191e810c19729de860ea",
"invitedByName": "John Admin",
"expiresAt": "2026-02-16T10:00:00.000Z",
"createdAt": "2026-02-09T10:00:00.000Z"
}
]
}

Invitation Statuses

StatusDescription
pendingAwaiting acceptance
acceptedUser joined organization
expiredToken expired (7+ days)

DELETE /api/invitations/:id

Revoke a pending invitation.

Authentication: Required
Authorization: Admin role only

Parameters

ParameterTypeDescription
idstringInvitation ID (MongoDB ObjectId)

Response (200 OK)

{
"success": true,
"message": "Invitation revoked successfully"
}

Error Responses

StatusErrorDescription
400Invalid invitation IDInvalid ObjectId format
401Authentication requiredNo valid JWT token
403ForbiddenUser is not an admin
404Invitation not foundID not found or different org
500Failed to revoke invitationInternal server error

GET /api/invitations/validate/:token

Validate an invitation token (public endpoint).

Authentication: Not required

Parameters

ParameterTypeDescription
tokenstring64-character hex token from email

Response (200 OK - Valid)

{
"success": true,
"valid": true,
"organizationName": "Acme Corp",
"role": "developer",
"inviterName": "John Admin",
"userExists": false
}

Response (404 - Invalid/Expired)

{
"success": false,
"valid": false,
"error": "Invitation has expired"
}

Error Responses

StatusErrorDescription
400Invalid token formatToken not 64 hex chars
404Invitation not found or already usedToken invalid
404Invitation has expiredPast 7-day window
500Failed to validate invitationInternal server error

POST /api/invitations/accept

Accept an invitation (for existing users who login first).

Authentication: Required

Request Body

{
"token": "a1b2c3d4e5f6..."
}

Response (200 OK)

{
"success": true,
"message": "Successfully joined Acme Corp",
"organization": {
"id": "507f191e810c19729de860ea",
"name": "Acme Corp"
}
}

Flow

  1. User receives invitation email
  2. User clicks link → validates token
  3. If new user: Signs up via /api/auth/signup with inviteToken
  4. If existing user: Logs in, then calls this endpoint with token

Error Responses

StatusErrorDescription
400Missing tokenToken not provided
400Invalid token formatToken format invalid
401Authentication requiredUser not logged in
403Email mismatchLogged-in email ≠ invitation email
404Invalid or expired invitationToken not found
404Invitation has expiredPast 7-day window
500Failed to accept invitationInternal server error

Invitation Flow Diagram

┌─────────────────┐
│ Admin sends │
│ POST /api/ │
│ invitations │
└────────┬────────┘


┌─────────────────┐
│ Token generated │
│ Hash stored │
│ Email sent │
└────────┬────────┘


┌─────────────────┐ ┌─────────────────┐
│ GET /validate/ │────▶│ Valid? │
│ :token │ │ │
└─────────────────┘ └────────┬────────┘

┌──────────────────┴──────────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ New User │ │ Existing User │
│ │ │ │
│ POST /signup │ │ POST /login │
│ with inviteToken│ │ then │
│ │ │ POST /accept │
└────────┬────────┘ └────────┬────────┘
│ │
└──────────────┬───────────────────┘


┌─────────────────┐
│ User joins org │
│ Token consumed │
└─────────────────┘

Rate Limiting

EndpointLimitWindow
POST /api/invitations5 requests1 minute
Other endpoints100 requests1 minute