1. Docs
  2. API Reference
  3. Create an invite

Create an invite

POST/portal/v1/accounts/{accountSlug}/applications/{appSlug}/environments/{envSlug}/identity-invites

Authentication

  • Bearer Token Authorization

    JWT access token

Request body

  • client_idstring

    OAuth client ID — determines which app the invite links to. If omitted, uses Canopy hosted fallback.

  • intentenum: "activate" | "password_reset" | "onboard"

    Optional. `activate` (default) creates a net-new identity OR — if an identity with this email already exists in the Account but has no active membership in this App — auto-derives an `add_to_app` invite that adds them to this App without touching their existing password. `password_reset` is the explicit admin-driven credential-rotation flow for an existing identity; it cannot carry a role/node assignment. The legacy `onboard` value is accepted and treated as `activate`.

  • emailstring*
  • first_namestring

    Required for `activate`. Ignored for `add_to_app` (the existing identity's name wins) and for `password_reset`.

  • last_namestring

    Required for `activate`. Ignored for `add_to_app` and `password_reset`.

  • role_idstring

    Role ID — required if node_id is provided

  • node_idstring

    Node ID — required if role_id is provided

  • send_emailboolean

    Whether Canopy should send the invite email. Set false to suppress delivery and handle it yourself — the API response includes accept_url with the tokenized link. Defaults to true.

Code samples

cURLJavaScriptPythonGo
curl -X POST "https://api.canopy.dev/portal/v1/accounts/{accountSlug}/applications/{appSlug}/environments/{envSlug}/identity-invites" \
  -H "Authorization: Bearer $CANOPY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "string",
    "intent": "activate",
    "email": "string",
    "first_name": "string",
    "last_name": "string",
    "role_id": "string",
    "node_id": "string",
    "send_email": true
  }'

Responses

201 Invite created
{
  "id": "string",
  "email": "string",
  "intent": "activate",
  "first_name": "string",
  "last_name": "string",
  "name": "string",
  "role_id": "string",
  "node_id": "string",
  "has_initial_assignment": false,
  "status": "pending",
  "expires_at": "2026-04-20T12:00:00.000Z",
  "invited_by": "string",
  "created_at": "2026-04-20T12:00:00.000Z"
}

application/json

  • idstring*
  • emailstring*
  • intentenum: "activate" | "add_to_app" | "password_reset" | "onboard"*

    Final intent stamped on the invite at create time. `activate` is the auto-derived default for net-new identities; `add_to_app` is auto-derived when the email matches an existing account-level identity that has no membership in this App; `password_reset` is admin-explicit. `onboard` may appear on rows created before the rename.

  • first_namestring*
  • last_namestring*
  • namestring*
  • role_idstring
  • node_idstring
  • has_initial_assignmentboolean*
  • statusenum: "pending" | "accepted" | "revoked" | "expired"*
  • expires_atstring (date-time)*
  • invited_bystring*
  • created_atstring (date-time)*
401 Invalid or expired token
403 This token is not authorized for this endpoint (wrong principal type — e.g., admin token on identity-only endpoint, or vice versa)

Returned object

On this page

Related endpoints

GETList invites
GETGet invite summary
POSTBulk-create invites
POSTResend an invite
DELETERevoke an invite