Skip to main content
The invitation system allows account owners to invite users to join their accounts. Invitations are sent via email and include encrypted account keys for secure data sharing.

Create Invitation

Create a new invitation to add a member to the account. Only the account owner can create invitations.

Authentication

Requires authentication token and CSRF token.

Path Parameters

id
string
required
The account ID (UUID)

Request Body

email
string
required
Email address of the user to invite
encryptedKey
string
Encrypted account key to share with the invited user. This allows the invited user to decrypt account data.

Response

invitation
object
The created invitation object
Relative path to the invitation page (e.g., /invite/{token})

Example Request

curl -X POST https://api.example.com/api/accounts/a1b2c3d4-e5f6-7890-abcd-ef1234567890/invitations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: YOUR_CSRF_TOKEN" \
  -d '{
    "email": "[email protected]",
    "encryptedKey": "encrypted_account_key_here"
  }'

Example Response

{
  "invitation": {
    "id": "inv-uuid-here",
    "account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "invited_by": "owner-user-id",
    "email": "[email protected]",
    "token": "64-character-hex-token-here",
    "status": "pending",
    "expires_at": "2026-03-06T10:30:00.000Z",
    "created_at": "2026-03-05T10:30:00.000Z"
  },
  "inviteLink": "/invite/64-character-hex-token-here"
}

Error Responses

400 Bad Request

{
  "error": "Email es requerido"
}
{
  "error": "Este usuario ya es miembro de la cuenta"
}

403 Forbidden

{
  "error": "Solo el propietario puede invitar miembros"
}

List Invitations

Get all invitations for an account. Both owners and members can view invitations.

Authentication

Requires authentication token.

Path Parameters

id
string
required
The account ID (UUID)

Response

invitations
array
Array of invitation objects, ordered by creation date (newest first)

Example Request

curl -X GET https://api.example.com/api/accounts/a1b2c3d4-e5f6-7890-abcd-ef1234567890/invitations \
  -H "Authorization: Bearer YOUR_TOKEN"

Example Response

{
  "invitations": [
    {
      "id": "inv-uuid-1",
      "account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "invited_by": "owner-user-id",
      "email": "[email protected]",
      "token": "token-1",
      "status": "pending",
      "invited_user_id": null,
      "expires_at": "2026-03-06T10:30:00.000Z",
      "created_at": "2026-03-05T10:30:00.000Z",
      "accepted_at": null
    },
    {
      "id": "inv-uuid-2",
      "account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "invited_by": "owner-user-id",
      "email": "[email protected]",
      "token": "token-2",
      "status": "accepted",
      "invited_user_id": "user-uuid",
      "expires_at": "2026-03-05T09:00:00.000Z",
      "created_at": "2026-03-04T09:00:00.000Z",
      "accepted_at": "2026-03-04T11:30:00.000Z"
    }
  ]
}

Get Invitation by Token

View invitation details using the invitation token. This endpoint is public and does not require authentication.

Path Parameters

token
string
required
The invitation token (64-character hex string)

Response

invitation
object
Invitation details with account information
isExpired
boolean
Whether the invitation has expired

Example Request

curl -X GET https://api.example.com/api/invitations/64-character-hex-token-here

Example Response

{
  "invitation": {
    "status": "pending",
    "account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "account_name": "Personal Finances",
    "invited_by_name": "John Doe",
    "expires_at": "2026-03-06T10:30:00.000Z",
    "encrypted_key": "encrypted_key_here"
  },
  "isExpired": false
}

Error Responses

404 Not Found

{
  "error": "Invitación no encontrada"
}

Accept Invitation

Accept an invitation and join the account. The authenticated user must have an email matching the invitation.

Authentication

Requires authentication token.

Path Parameters

token
string
required
The invitation token

Response

message
string
Success message
invitation
object
Updated invitation object with accepted status
account
object
Basic account information

Example Request

curl -X POST https://api.example.com/api/invitations/64-character-hex-token-here/accept \
  -H "Authorization: Bearer YOUR_TOKEN"

Example Response

{
  "message": "Invitación aceptada",
  "invitation": {
    "id": "inv-uuid",
    "account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "accepted",
    "invited_user_id": "user-uuid",
    "accepted_at": "2026-03-05T10:35:00.000Z"
  },
  "account": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": ""
  }
}

Error Responses

400 Bad Request

{
  "error": "La invitación ha expirado"
}
{
  "error": "La invitación ya fue aceptada"
}
{
  "error": "Esta invitación es para otro email"
}
{
  "error": "Ya eres miembro de esta cuenta"
}

Update Invitation Key

Update the encrypted key for an existing pending invitation. Only the account owner can update invitation keys.

Authentication

Requires authentication token and CSRF token.

Path Parameters

id
string
required
The account ID (UUID)
invitationId
string
required
The invitation ID (UUID)

Request Body

encryptedKey
string
required
The new encrypted account key

Response

success
boolean
Indicates if the operation was successful

Example Request

curl -X PATCH https://api.example.com/api/accounts/a1b2c3d4-e5f6-7890-abcd-ef1234567890/invitations/inv-uuid/key \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: YOUR_CSRF_TOKEN" \
  -d '{
    "encryptedKey": "new_encrypted_key_here"
  }'

Example Response

{
  "success": true
}

Error Responses

400 Bad Request

{
  "error": "encryptedKey es requerido"
}

403 Forbidden

{
  "error": "Solo el propietario puede actualizar invitaciones"
}

Revoke Invitation

Revoke a pending invitation. Only the account owner can revoke invitations.

Authentication

Requires authentication token and CSRF token.

Path Parameters

id
string
required
The account ID (UUID)
invitationId
string
required
The invitation ID (UUID)

Response

message
string
Success message

Example Request

curl -X DELETE https://api.example.com/api/accounts/a1b2c3d4-e5f6-7890-abcd-ef1234567890/invitations/inv-uuid \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-CSRF-Token: YOUR_CSRF_TOKEN"

Example Response

{
  "message": "Invitación revocada"
}

Error Responses

403 Forbidden

{
  "error": "Solo el propietario puede revocar invitaciones"
}

404 Not Found

{
  "error": "Invitación no encontrada o ya procesada"
}

Invitation Flow

The invitation system follows this workflow:
  1. Owner creates invitation: The account owner creates an invitation with the invitee’s email address and optionally includes an encrypted account key.
  2. Token generation: A unique 64-character hex token is generated, valid for 24 hours.
  3. Invitation sent: The invitee receives the invitation link (/invite/{token}).
  4. Public verification: Anyone with the token can view basic invitation details (no auth required).
  5. User accepts: The invited user (authenticated) accepts the invitation. The system verifies:
    • The token is valid and not expired
    • The user’s email matches the invitation email
    • The user is not already a member
  6. Member added: Upon acceptance, the user is added to the account with the member role.

Key Sharing

The encryptedKey field enables secure sharing of account encryption keys:
  • The owner encrypts the account key before creating the invitation
  • The encrypted key is stored with the invitation
  • When the invitee accepts, they can decrypt the key and access encrypted account data
  • Keys can be updated on pending invitations using the PATCH endpoint

Invitation States

  • pending: Invitation created and waiting for acceptance
  • accepted: User has joined the account
  • expired: Invitation passed the 24-hour expiration time
  • revoked: Owner cancelled the invitation before acceptance

Notes

  • Invitations expire after 24 hours
  • If a pending invitation exists for an email, creating a new one refreshes the token and expiration
  • Only pending invitations can be revoked
  • Users cannot accept invitations for accounts they’re already members of
  • The invitation email must match the accepting user’s email

Build docs developers (and LLMs) love