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

# Import an application's access

> Imports the complete access list for one application. Users, resources and permissions are matched by email and title. **Any access not present in the body is removed.** An email matching no known user creates one. If any row cannot be resolved, nothing is written and every rejected row is listed in the response. Importing into an application with an active access-syncing integration is permitted; the next scheduled sync will overwrite what the import wrote. Because this call replaces all of an application's access, send a unique `Idempotency-Key` header so an accidentally repeated request is rejected rather than re-applied.

## This is a full replace, not a merge

Import sends the **complete** access list for one application. Users, resources and
permissions are matched by email and title, and **any access not present in the body is
removed** — this is a replace, not an incremental update. An email matching no known user
creates one, so send the full intended state every time, not just the rows you want to
add or change.

The write is all-or-nothing: if any row cannot be resolved, nothing is written and every
rejected row is listed in the response. Importing into an application with an active
access-syncing integration is allowed, but the next scheduled sync will overwrite whatever
the import wrote.

<Warning>
  Because this call replaces **all** of an application's access, an omission is a deletion.
  Read back the current state with
  [List access states](/api-reference/access-states/list) and build the body from there
  rather than from a partial list.
</Warning>

## Long-running request — combine with idempotency

Replacing every user, resource and permission for an application is a large operation. For
a big application the request can be **long-running**, and the underlying TCP connection
may be held open long enough that a proxy, load balancer or client timeout drops it before
AccessOwl responds — even though the import is still being applied on the server.

A plain retry after such a timeout would re-run the whole replace. To retry safely, send a
unique `Idempotency-Key` header and reuse **the same key** on every retry of that import —
a repeat then returns `409 Conflict` instead of re-applying the replace.

<Tip>
  See [Idempotency](/api-reference/introduction#idempotency) for the full contract — key
  format, how `409`/`422` responses behave, and retention.
</Tip>


## OpenAPI

````yaml PUT /api/v1/applications/{application_id}/access_states
openapi: 3.0.0
info:
  description: REST API for AccessOwl third-party integrations
  title: AccessOwl API
  version: 1.0.0
servers:
  - url: https://api.accessowl.com
    variables: {}
security:
  - bearer: []
tags: []
paths:
  /api/v1/applications/{application_id}/access_states:
    put:
      tags:
        - access_states
      summary: Import an application's access
      description: >-
        Imports the complete access list for one application. Users, resources
        and permissions are matched by email and title. **Any access not present
        in the body is removed.** An email matching no known user creates one.
        If any row cannot be resolved, nothing is written and every rejected row
        is listed in the response. Importing into an application with an active
        access-syncing integration is permitted; the next scheduled sync will
        overwrite what the import wrote. Because this call replaces all of an
        application's access, send a unique `Idempotency-Key` header so an
        accidentally repeated request is rejected rather than re-applied.
      operationId: AccessOwlApi.AccessStateController.import
      parameters:
        - description: >-
            Optional key (1–255 chars) for safely retrying a request. Reusing
            the same key for the same request returns `409 Conflict` and is not
            processed again — this confirms the request was already received.
            Keys are retained for 14 days.
          in: header
          name: Idempotency-Key
          required: false
          schema:
            maxLength: 255
            minLength: 1
            type: string
        - description: Application ID
          in: path
          name: application_id
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportAccessStates'
        description: Complete access list
        required: false
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessImportResult'
          description: Import result
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestError'
          description: Bad request
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Not found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Validation error
      callbacks: {}
components:
  schemas:
    ImportAccessStates:
      description: >-
        The complete access list for one application. Any access not listed is
        removed.
      example:
        access:
          - permissions:
              - Admin
            resource: Billing
            user_email: ana@example.com
      properties:
        access:
          description: One entry per user and resource
          items:
            properties:
              permissions:
                description: Permission titles held on the resource
                items:
                  type: string
                minItems: 1
                type: array
              resource:
                description: >-
                  Resource title. May be omitted for an application with a
                  single resource.
                nullable: true
                type: string
              user_email:
                description: Email of the user
                type: string
            required:
              - user_email
              - permissions
            type: object
          type: array
      required:
        - access
      title: ImportAccessStates
      type: object
    AccessImportResult:
      description: Counts of the changes the import made
      example:
        data:
          created: 12
          deleted: 5
          unchanged: 40
          updated: 3
      properties:
        data:
          properties:
            created:
              type: integer
            deleted:
              type: integer
            unchanged:
              type: integer
            updated:
              type: integer
          required:
            - created
            - updated
            - deleted
            - unchanged
          type: object
      required:
        - data
      title: AccessImportResult
      type: object
    BadRequestError:
      additionalProperties: false
      description: Error response for a malformed or invalid request
      example:
        error: invalid_params
        errors:
          - field: application_id
            messages:
              - is invalid
        message: Invalid request parameters
      properties:
        error:
          description: Error code
          example: invalid_params
          type: string
        errors:
          description: >-
            One entry per rejected parameter. Present when a query or path
            parameter fails validation, and omitted for other bad requests.
          items:
            additionalProperties: false
            properties:
              field:
                description: Name of the rejected parameter
                example: application_id
                type: string
              messages:
                description: Reasons the value was rejected
                example:
                  - is invalid
                items:
                  type: string
                type: array
            required:
              - field
              - messages
            type: object
          type: array
        message:
          description: Human-readable error message
          example: Invalid request parameters
          type: string
      required:
        - error
        - message
      title: BadRequestError
      type: object
    Error:
      description: Standard error response
      example:
        error: not_found
        message: Resource not found
      properties:
        error:
          description: Error code
          example: not_found
          type: string
        errors:
          additionalProperties:
            items:
              type: string
            type: array
          description: >-
            Field-specific validation errors, keyed by field name. Present on
            422 responses. A 400 response reports its errors as a list instead —
            see the BadRequestError schema.
          example:
            email:
              - has invalid format
            first_name:
              - can't be blank
          type: object
        message:
          description: Human-readable error message
          example: Resource not found
          type: string
      required:
        - error
        - message
      title: Error
      type: object
  securitySchemes:
    bearer:
      description: >-
        Bearer token authentication. Pass your AccessOwl API token in the
        `Authorization` header as `Bearer <token>`.
      scheme: bearer
      type: http

````