---
title: "Bulk-invite a member across companies"
method: POST
path: "/v1/company_memberships/create_many"
tags: ["Company membership"]
---

# Bulk-invite a member across companies

`POST /v1/company_memberships/create_many`

## Request

- Base URL: `https://api.cardda.com`
- URL: `https://api.cardda.com/v1/company_memberships/create_many`
- Auth: HTTP bearer

Invites the same email (with one role) to multiple companies at once, sharing
a single invitation token and sending a single email.

The invitation is **partial**: companies where the email cannot be invited are
skipped and the rest are processed. Each skipped company comes back in
`skipped` with a stable `reason`:

- `already_member`: the email already belongs to a member of that company.
- `owner_invitation`: the email has a pending `owner` invitation there and the
  caller is not an owner of that company, so it cannot be moved.
- `role_not_found`: the company does not define the requested role.
- `already_invited`: another invitation for that company was created at the
  same time.

A pending invitation for the same email in one of the selected companies is
not skipped: it is moved to the new token with the new role and returned in
`reinvited`. Pending invitations in companies that were not selected keep
their previous link.

Permissions are not skipped: the caller needs `members_management` in every
target company, and assigning the `owner` role requires the caller to be an
owner of each one; otherwise the whole request is rejected with `403`.

At most **200 companies** per request: larger lists are rejected with `422`
(`too_many_companies`) and nothing is processed, so split them into batches of
up to 200.

Every `403`, `412` and `422` carries a stable `code` (`forbidden`,
`owner_only`, `parameter_missing`, `too_many_companies`, `invalid_companies`,
`nothing_to_invite`); branch on it instead of on the English `message`.

## Parameters

- `#/paths/~1v1~1users/get/parameters/0` (unresolved $ref)

## Request body

- object
  - `email` string, email, required
  - `role` string, required
  - `company_ids` string[], required: Company UUIDs to invite the email into. At most 200 per request.

## Response `201`

At least one company was processed.

- union
  - object: At least one new pending membership.
    - `created` CompanyMembership[], required: New pending memberships, one per company.
      - `id` string, uuid, required
      - `user_id` string, nullable: Firebase UID of the member. Null while the invitation is still pending.
      - `company_id` string, uuid, required
      - `email` string, nullable
      - `role` string: Role name (e.g. `owner`, `admin`, `member`, or a custom company role name).
      - `status` 'pending' | 'active' | 'canceled'
      - `legal_representative` boolean
      - `has_powers_to_act` boolean, nullable
      - `partner` boolean
      - `partner_type` integer, nullable
      - `participation_rate` number, nullable: Ownership participation percentage (0-100).
      - `is_indirect_participation_corporate` boolean, nullable
      - `company_role_id` string, uuid, nullable
      - `permissions` object[]: Permissions granted to the membership (only `id` and `name` are returned). **Only included by the list endpoint** (`GET /v1/company_memberships`); the create/update/destroy/resend/create_many responses do not embed it.
        - `id` string, uuid
        - `name` string
      - `created_at` string, date-time
      - `updated_at` string, date-time
    - `reinvited` object[], required: Earlier pending invitations moved to the new token and role.
      - `company_id` string, uuid, required
      - `membership_id` string, uuid, required
      - `previous_role` string, required
    - `skipped` object[], required
      - `company_id` string, uuid, required
      - `reason` 'already_member' | 'owner_invitation' | 'role_not_found' | 'already_invited', required
  - object: At least one earlier pending invitation moved to the new token.
    - `reinvited` object[], required: Earlier pending invitations moved to the new token and role.
      - `company_id` string, uuid, required
      - `membership_id` string, uuid, required
      - `previous_role` string, required
    - `created` CompanyMembership[], required: New pending memberships, one per company.
      - `id` string, uuid, required
      - `user_id` string, nullable: Firebase UID of the member. Null while the invitation is still pending.
      - `company_id` string, uuid, required
      - `email` string, nullable
      - `role` string: Role name (e.g. `owner`, `admin`, `member`, or a custom company role name).
      - `status` 'pending' | 'active' | 'canceled'
      - `legal_representative` boolean
      - `has_powers_to_act` boolean, nullable
      - `partner` boolean
      - `partner_type` integer, nullable
      - `participation_rate` number, nullable: Ownership participation percentage (0-100).
      - `is_indirect_participation_corporate` boolean, nullable
      - `company_role_id` string, uuid, nullable
      - `permissions` object[]: Permissions granted to the membership (only `id` and `name` are returned). **Only included by the list endpoint** (`GET /v1/company_memberships`); the create/update/destroy/resend/create_many responses do not embed it.
        - `id` string, uuid
        - `name` string
      - `created_at` string, date-time
      - `updated_at` string, date-time
    - `skipped` object[], required
      - `company_id` string, uuid, required
      - `reason` 'already_member' | 'owner_invitation' | 'role_not_found' | 'already_invited', required

## Other responses

- `401`: Unauthorized
- `403`: The caller lacks `members_management`, or is not an owner while assigning `owner`, in the listed companies. Nothing is created.
- `412`: `email`, `role` or `company_ids` is missing or empty (`company_ids: []` included).
- `422`: Nothing was processed. `code` says why: `nothing_to_invite` (every company was skipped, `skipped` lists why), `invalid_companies` (some `company_ids` are not available to the caller, listed in `company_ids`) or `too_many_companies` (more than 200 `company_ids`).

---

[API](https://skmtc.dev/cardda/apis/organization-api.md) - [All operations](https://skmtc.dev/cardda/apis/organization-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cardda/apis/organization-api/revisions/32a4430278a8?raw)
