> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowpayroll.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Replace a person's direct grants

> Declarative: afterwards they hold a direct grant on exactly the organisations listed, and the difference from their current grants is worked out here. Every organisation being added is checked against what you can reach, so nobody grants wider than they hold. 404 when any organisation named is not yours; 400 `user_access_would_be_empty` when the result would leave them reaching nothing; 409 `cannot_remove_own_last_access` when it would remove your own last access.

This does **not** describe account-wide access. Somebody holding it reaches every organisation whatever this list says, and sending an empty list does not remove it — read `coversWholeCustomer` in the response. To change one organisation without restating the rest, use `PUT` or `DELETE /users/{principalId}/organisations/{organisationId}`, which are also safe when two administrators edit at once.

For a guest, an empty list takes back everything you granted — that is how guest access ends, and their own account elsewhere is untouched.



## OpenAPI

````yaml /api-reference/specs/administration.json put /users/{principalId}/organisations
openapi: 3.0.1
info:
  title: Administration API
  description: >-
    Manage your Flow Payroll account: the organisations it owns, the people who
    can sign in to it, the API tokens it holds, its brand, and a feed of recent
    administration activity. Every resource is scoped to the account your
    credentials belong to, so no request ever names a customer and the
    `X-Org-Id` header is not used.
  version: v1
servers:
  - url: https://api.sandbox.flowpayroll.ai/v1/administration
security:
  - X-Auth-Token: []
tags:
  - name: Customer
    description: >-
      Your account: the customer every other resource on this API belongs to.
      Read it and rename it.
  - name: Organisations
    description: >-
      The organisations your account owns: list them with headcounts and your
      access to each, get one in full, and add one or several at a time.
  - name: Users
    description: >-
      The people who can sign in to your account: list, invite (one or many),
      resend invitations, and manage each person's direct grants and
      account-wide access.
  - name: API tokens
    description: >-
      The client credentials your integrations authenticate with: create (the
      secret is shown once), rename, rotate, revoke, and manage which
      organisations each token reaches.
  - name: Activity
    description: Recent administration actions in your account, newest first.
paths:
  /users/{principalId}/organisations:
    put:
      tags:
        - Users
      summary: Replace a person's direct grants
      description: >-
        Declarative: afterwards they hold a direct grant on exactly the
        organisations listed, and the difference from their current grants is
        worked out here. Every organisation being added is checked against what
        you can reach, so nobody grants wider than they hold. 404 when any
        organisation named is not yours; 400 `user_access_would_be_empty` when
        the result would leave them reaching nothing; 409
        `cannot_remove_own_last_access` when it would remove your own last
        access.


        This does **not** describe account-wide access. Somebody holding it
        reaches every organisation whatever this list says, and sending an empty
        list does not remove it — read `coversWholeCustomer` in the response. To
        change one organisation without restating the rest, use `PUT` or `DELETE
        /users/{principalId}/organisations/{organisationId}`, which are also
        safe when two administrators edit at once.


        For a guest, an empty list takes back everything you granted — that is
        how guest access ends, and their own account elsewhere is untouched.
      operationId: ReplaceUserOrganisations
      parameters:
        - name: principalId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReplaceUserOrganisationsRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserOrganisationsResponseResponseBody'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
components:
  schemas:
    ReplaceUserOrganisationsRequest:
      type: object
      properties:
        organisationIds:
          type: array
          items:
            type: string
          description: >-
            The complete set of organisations they hold a direct grant on
            afterwards.
          nullable: true
      additionalProperties: false
      description: >-
        Replaces the whole set of organisations a person holds a direct grant
        on. Does not affect

        account-wide access.
    UserOrganisationsResponseResponseBody:
      type: object
      properties:
        message:
          $ref: '#/components/schemas/MessageWithTokenResponse'
        content:
          $ref: '#/components/schemas/UserOrganisationsResponseContentResponse'
        validationIssues:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssue'
          nullable: true
      additionalProperties: false
    ObjectResponseBody:
      type: object
      properties:
        message:
          $ref: '#/components/schemas/MessageWithTokenResponse'
        content:
          $ref: '#/components/schemas/ObjectContentResponse'
        validationIssues:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssue'
          nullable: true
      additionalProperties: false
    MessageWithTokenResponse:
      type: object
      properties:
        text:
          type: string
        token:
          type: string
        tokenArguments:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssueArgument'
          nullable: true
      additionalProperties: false
    UserOrganisationsResponseContentResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/UserOrganisationsResponse'
        metadata:
          $ref: '#/components/schemas/ContentMetadataResponse'
      additionalProperties: false
    ValidationIssue:
      type: object
      properties:
        field:
          type: string
        reason:
          type: string
        reasonToken:
          type: string
        reasonTokenArguments:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssueArgument'
          nullable: true
      additionalProperties: false
    ObjectContentResponse:
      type: object
      properties:
        data:
          nullable: true
        metadata:
          $ref: '#/components/schemas/ContentMetadataResponse'
      additionalProperties: false
    ValidationIssueArgument:
      type: object
      properties:
        name:
          type: string
        value:
          nullable: true
      additionalProperties: false
    UserOrganisationsResponse:
      type: object
      properties:
        principalId:
          type: string
          description: The person.
        organisationIds:
          type: array
          items:
            type: string
          description: Every organisation they hold a direct grant on.
        coversWholeCustomer:
          type: boolean
          description: >-
            Whether they also hold account-wide access, which reaches every
            organisation the account owns,

            including ones added later. Read this before treating an empty list
            as no access. Nothing on the

            organisations collection can create or remove it.
      additionalProperties: false
      description: The organisations one person reaches, after a read or a change.
    ContentMetadataResponse:
      type: object
      properties:
        dateFormat:
          type: string
        dateTimeFormat:
          type: string
        paginationToken:
          type: string
          nullable: true
      additionalProperties: false
  securitySchemes:
    X-Auth-Token:
      type: apiKey
      description: FlowPayroll JWT (raw token, no Bearer prefix)
      name: X-Auth-Token
      in: header

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.