Invitation Endpoint Reference

Request and response contracts for creating, listing, cancelling, accepting, and declining organization invitations.

AuthOS release 0.8.2 API v1 Latest-only documentation
Updated Jul 15, 2026 Edit this page
On this page

Organization Admin Endpoints

POST /api/organizations/:org_slug/invitations

Create a new invitation to join an organization. The invitation is sent via email (if SMTP is configured) and can be accepted by the invited user.

Authentication: Required (Organization Management JWT)

Permissions: Organization owner or admin

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
email string Yes Email address of the user to invite
role string Yes Role to assign: owner, admin, or member

Request Headers:

Authorization: Bearer {jwt_token}
Content-Type: application/json

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/invitations \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "newuser@example.com",
    "role": "member"
  }'

Response (200 OK):

{
  "invitation": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "org_id": "org-123",
    "email": "newuser@example.com",
    "role": "member",
    "invited_by": "user-456",
    "status": "pending",
    "token": "hashed-token-value",
    "expires_at": "2025-01-22T10:30:00Z",
    "created_at": "2025-01-15T10:30:00Z"
  },
  "inviter": {
    "id": "user-456",
    "email": "admin@acme.com",
    "created_at": "2024-01-01T00:00:00Z"
  },
  "token": "550e8400-e29b-41d4-a716-446655440000"
}

Response Fields:

Invitation Object:

  • id (string): Invitation unique identifier
  • org_id (string): Organization ID
  • email (string): Invited user’s email
  • role (string): Assigned role (owner, admin, or member)
  • invited_by (string): User ID of inviter
  • status (string): Invitation status (pending, accepted, rejected, cancelled)
  • token (string): Hashed token (for internal use)
  • expires_at (string): ISO 8601 expiration timestamp
  • created_at (string): ISO 8601 creation timestamp

Inviter Object:

  • id (string): Inviter’s user ID
  • email (string): Inviter’s email
  • created_at (string): Inviter’s account creation timestamp

Token Field:

  • token (string): Plaintext token for email links (only returned once on creation)

Error Responses:

  • 400 Bad Request: Invalid role, user already a member, or invitation already sent
    {
      "error": "User is already a member of this organization"
    }
    
    {
      "error": "Invitation already sent"
    }
    
    {
      "error": "Invalid role. Must be one of: owner, admin, member"
    }
    
  • 401 Unauthorized: Missing or invalid JWT token
  • 403 Forbidden: User is not an admin or owner
  • 404 Not Found: Organization not found

Important Notes:

  • The plaintext token is only returned once upon creation for use in email links
  • Valid roles are: owner, admin, member
  • Cannot invite users who are already members
  • Cannot create duplicate pending invitations for the same email
  • Invitations expire after 7 days by default
  • Member limit enforcement happens during invitation acceptance, not creation
  • A webhook event user.invited is published to configured webhooks

Email Integration: If SMTP is configured for the organization, an invitation email is automatically sent with:

  • Invitation details (organization name, inviter name, role)
  • Direct acceptance link: {BASE_URL}/invitations/accept?token={token}
  • Expiration information

GET /api/organizations/:org_slug/invitations

List all invitations for an organization with pagination support. Includes invitation details and inviter information.

Authentication: Required (Organization Management JWT)

Permissions: Organization owner or admin

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (minimum: 1)
limit integer No 50 Results per page (1-100)
status string No - Filter by status (pending, accepted, rejected, cancelled)

Request Headers:

Authorization: Bearer {jwt_token}

Example Request:

curl -X GET "https://sso.example.com/api/organizations/acme-corp/invitations?page=1&limit=20" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response (200 OK):

[
  {
    "invitation": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "newuser@example.com",
      "role": "member",
      "status": "pending",
      "token": "hashed-token",
      "expires_at": "2025-01-22T10:30:00Z",
      "created_at": "2025-01-15T10:30:00Z"
    },
    "inviter": {
      "id": "user-456",
      "email": "admin@acme.com",
      "created_at": "2024-01-01T00:00:00Z"
    }
  },
  {
    "invitation": {
      "id": "660e8400-e29b-41d4-a716-446655440111",
      "email": "another@example.com",
      "role": "admin",
      "status": "accepted",
      "token": "hashed-token",
      "expires_at": "2025-01-20T08:15:00Z",
      "created_at": "2025-01-13T08:15:00Z"
    },
    "inviter": {
      "id": "user-789",
      "email": "owner@acme.com",
      "created_at": "2023-12-01T00:00:00Z"
    }
  }
]

Response: Array of invitation objects with inviter details

Error Responses:

  • 401 Unauthorized: Missing or invalid JWT token
  • 403 Forbidden: User is not an admin or owner
  • 404 Not Found: Organization not found

Pagination:

  • Default limit: 50 invitations per page
  • Maximum limit: 100 invitations per page
  • Page numbers start at 1
  • Results are ordered by creation date (newest first)

POST /api/organizations/:org_slug/invitations/:invitation_id

Cancel a pending invitation. Only pending invitations can be cancelled.

Authentication: Required (Organization Management JWT)

Permissions: Organization owner or admin

Path Parameters:

Parameter Type Description
org_slug string Organization slug
invitation_id string Invitation ID

Query Parameters: None

Request Body: None

Request Headers:

Authorization: Bearer {jwt_token}

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/invitations/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response: 200 OK with empty JSON object {}

Error Responses:

  • 401 Unauthorized: Missing or invalid JWT token
  • 403 Forbidden: User is not an admin or owner
  • 404 Not Found: Invitation not found or already processed
    {
      "error": "Invitation not found or already processed"
    }
    

Important Notes:

  • Only pending invitations can be cancelled
  • Accepted, rejected, or expired invitations cannot be cancelled
  • Cancelled invitations cannot be reactivated (create a new invitation instead)
  • A webhook event invitation.revoked is published to configured webhooks

User Endpoints

GET /api/invitations

List all pending invitations for the authenticated user across all organizations.

Authentication: Required (any valid JWT)

Permissions: Any authenticated user

Query Parameters: None

Request Headers:

Authorization: Bearer {jwt_token}

Example Request:

curl -X GET https://sso.example.com/api/invitations \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response (200 OK):

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "role": "member",
    "token": "hashed-token",
    "expires_at": "2025-01-22T10:30:00Z",
    "created_at": "2025-01-15T10:30:00Z",
    "organization": {
      "slug": "acme-corp",
      "name": "Acme Corporation"
    }
  },
  {
    "id": "660e8400-e29b-41d4-a716-446655440111",
    "email": "user@example.com",
    "role": "admin",
    "token": "hashed-token",
    "expires_at": "2025-01-23T14:20:00Z",
    "created_at": "2025-01-16T14:20:00Z",
    "organization": {
      "slug": "techstart",
      "name": "TechStart Inc"
    }
  }
]

Response Fields:

  • Array of invitation objects with organization details
  • Only pending (not yet accepted/rejected/cancelled) invitations are returned
  • Only invitations for the authenticated user’s email address are returned
  • Expired invitations are excluded from results

Error Responses:

  • 401 Unauthorized: Missing or invalid JWT token

Use Cases:

  • Display pending invitations in user dashboard
  • Show organization join requests
  • Allow users to accept/decline multiple invitations

POST /api/invitations/accept

Accept a pending invitation using the invitation token. Creates a membership and optionally creates a user account if it doesn’t exist.

Authentication: Public (no authentication required)

Permissions: None (token-based)

Request Body:

Field Type Required Description
token string Yes Invitation token (UUID format)

Request Headers:

Content-Type: application/json

Example Request:

curl -X POST https://sso.example.com/api/invitations/accept \
  -H "Content-Type: application/json" \
  -d '{
    "token": "550e8400-e29b-41d4-a716-446655440000"
  }'

Response: 200 OK with empty JSON object {}

Error Responses:

  • 400 Bad Request: Invalid, expired, or already processed token
    {
      "error": "Invitation has expired"
    }
    
    {
      "error": "Invitation not found or already processed"
    }
    
    {
      "error": "Team limit reached"
    }
    
  • 500 Internal Server Error: Database error

Acceptance Flow:

  1. Token is hashed using SHA256 and looked up in database
  2. Invitation validation:
    • Must be in pending status
    • Must not be expired
    • Must pass team member limit check
  3. User account is found or created using the invitation email
  4. Membership is created with the specified role
  5. Invitation status is updated to accepted
  6. A webhook event invitation.accepted is published

Team Limit Enforcement:

  • Member count is checked against organization tier limits
  • Default free tier limit: 5 members
  • Organization-specific overrides: max_users field
  • Tier-specific limits: OrganizationTier.default_max_users
  • Invitation is rejected if limit is reached

User Creation:

  • If user with invitation email doesn’t exist, a new user account is created
  • User can then log in using OAuth or password (if configured)
  • User inherits the role specified in the invitation

Important Notes:

  • Token can only be used once
  • Expired invitations cannot be accepted
  • Team member limits are enforced at acceptance time
  • Transaction ensures atomic membership creation

POST /api/invitations/decline

Decline a pending invitation using the invitation token.

Authentication: Public (no authentication required)

Permissions: None (token-based)

Request Body:

Field Type Required Description
token string Yes Invitation token (UUID format)

Request Headers:

Content-Type: application/json

Example Request:

curl -X POST https://sso.example.com/api/invitations/decline \
  -H "Content-Type: application/json" \
  -d '{
    "token": "550e8400-e29b-41d4-a716-446655440000"
  }'

Response: 200 OK with empty JSON object {}

Error Responses:

  • 400 Bad Request: Invalid or already processed token
    {
      "error": "Invitation not found or already processed"
    }
    
    {
      "error": "Invitation has expired"
    }
    
  • 500 Internal Server Error: Database error

Decline Flow:

  1. Token is hashed using SHA256 and looked up in database
  2. Invitation validation:
    • Must be in pending status
    • Expiration is checked but allows declining expired invitations
  3. Invitation status is updated to rejected
  4. A webhook event invitation.declined is published

Important Notes:

  • Token can only be used once
  • Declining an invitation is permanent (cannot be undone)
  • Expired invitations can still be declined
  • No user account or membership is created

GET /invitations/accept/:token

Email link redirect endpoint for one-click invitation acceptance. This endpoint handles invitation acceptance via email links.

Authentication: Public (no authentication required)

Permissions: None (token-based)

Path Parameters:

Parameter Type Description
token string Invitation token from email

Example Request:

# User clicks link in email:
https://sso.example.com/invitations/accept/550e8400-e29b-41d4-a716-446655440000

Response: 301 Permanent Redirect to /invitations/accept?token={token}

Purpose: This is a convenience endpoint for email links. It redirects to the frontend application’s invitation acceptance page, which then calls the POST /api/invitations/accept endpoint with the token.

Flow:

  1. User receives invitation email with link
  2. User clicks link: GET /invitations/accept/ABC123
  3. Backend redirects to: /invitations/accept?token=ABC123 (frontend route)
  4. Frontend displays invitation details and acceptance UI
  5. User confirms acceptance
  6. Frontend calls POST /api/invitations/accept with token
  7. Backend processes acceptance and creates membership

Integration:

  • Configure your frontend router to handle the /invitations/accept route
  • Extract token from query parameters
  • Display invitation details (organization name, role, etc.)
  • Provide “Accept” and “Decline” buttons
  • Call the appropriate API endpoint based on user action