Teams > Membership

Creates a Membership

Changed on

Assign an employee to a team, meaning create a membership. For companies with nested teams, two extra semantics apply. Propagation: memberships are inherited upwards, so after adding an employee to a sub-team, inherited membership rows for its ancestor teams are materialized asynchronously — rows you did not create will appear in later reads. Reuse: if the employee already has a membership row on that team (typically an inherited one), no new row is created — the employee becomes a direct member of the team, the lead flag is applied when you send one, and the existing row (with its existing id) is returned instead of a new resource. Omitting lead leaves a reused row's leadership as it was, so replaying an addition never demotes a current lead; a genuinely new row is created without it. The response is still 201 when an existing row is reused, so compare the returned id against what you already hold to tell the two cases apart.

post/api/2026-10-01/resources/teams/memberships

Request

  • Base URL
    https://api.factorialhr.com
  • URL
    https://api.factorialhr.com/api/2026-10-01/resources/teams/memberships
  • Auth
    • OAuth 2
      Authorization code: https://id.factorialhr.com/oauth/authorize
      Token URL: https://id.factorialhr.com/api/oauth/token scopes: employees
    • or API key in header x-api-key

Request body

team_idstring required

Team id.

employee_idstring required

Employee id.

leadboolean

Makes the employee a lead of the team. Omit it to leave an existing row's flag untouched; a new row is created without leadership.

Example request

{
  "team_id": "3",
  "employee_id": "12",
  "lead": true
}

Response

CREATED

idstring required

Membership ID

company_idstring

Company ID of the membership

employee_idstring required

Employee ID of the membership

team_idstring required

Team ID of the membership

leadboolean required

Whether the employee is a lead of the team or not

source_team_idsstring[] required

IDs of the teams this membership originates from (nested teams). In a company with nested teams, a direct membership includes the team itself; an inherited one, the sub-team(s) where the employee is a direct member. Only populated on reads that compute source attribution — reads filtered by a single team, or by a single employee with with_source_attribution enabled. Empty otherwise, including create, update and delete responses, and always empty for companies without nested teams. An empty array does not distinguish "computed and genuinely empty" from "not computed for this read" or "could not be computed", so only apply attribution-dependent logic to a read you explicitly shaped for it. A team-anchored read stops attributing above roughly a thousand members of the filtered team: past that the attribution is not computed at all and every row comes back empty, behind a normal 200.

parent_team_idsstring[] required

IDs of the ancestor teams that receive an inherited membership through this row (nested teams) — the teams this membership rolls up into. Populated under the same conditions as source_team_ids; empty otherwise.

directboolean

Whether the employee is a direct member of the team (nested teams). Always present. true means direct member; false means the row exists only through inheritance from a sub-team; null means not computed for this read. Only computed on reads filtered by a single employee with with_source_attribution enabled — always null otherwise, including create, update and delete responses and companies without nested teams. null is also returned when directness could not be resolved for a transient reason, even with with_source_attribution enabled, so never treat null as false — retry the read instead.

Example response

{
  "id": "1",
  "company_id": "1",
  "employee_id": "12",
  "team_id": "3",
  "lead": true,
  "source_team_ids": [
    "3"
  ],
  "parent_team_ids": [
    "2"
  ]
}

Changes