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

# Import contacts into a list

> Queue a batch of contacts for creation or update and attach successful rows to an existing list. Requires `contacts:write` and `lists:write`. Supply a visible `listId`, an allowed current workspace `ownerId`, and 1–10,000 rows. The parsed request, serialized as JSON, is limited to 10,000,000 UTF-16 code units; this is not a byte-exact file-upload limit. The job owner overrides owner values inside rows.

HTTP `202` returns an import ID, state and processed count. It means accepted for background work, not that every row is valid or complete. Rows use the contact write shape; stable external IDs update existing visible contacts. Poll the import with the same credential and inspect every row result.

Persist an `Idempotency-Key`; retry the identical submission after an uncertain response to recover the same job. `413 import_too_large` requires smaller batches; `404 not_found` means the list is missing or inaccessible. Correct `403 invalid_owner` before submitting a new logical import.

See [asynchronous imports](/guides/contact-lists#asynchronous-imports).



## OpenAPI

````yaml /api/openapi.json post /imports
openapi: 3.1.0
info:
  title: PowerDialer API v2
  version: 2.0.0
  description: >-
    Connect your CRM, sales workspace or reporting tools to PowerDialer using
    scoped API keys. Manage contacts and calling lists, read call evidence and
    analytics, and receive signed events. All example records and IDs are
    synthetic; replace them with values from your workspace. Shared-key v1 is
    retired. API availability was verified on 2026-10-08; see /availability for
    historical data coverage. Legacy outbound webhooks use a separate contract.
servers:
  - url: https://api.migration.powerdialer.ai/api/public/v2
    description: Production API v2; availability verified on 2026-10-08.
security:
  - ApiKey: []
tags:
  - name: Authentication
  - name: Contacts
  - name: Calling lists
  - name: Imports
  - name: Calls
  - name: Synchronization
  - name: Analytics
  - name: Webhooks
  - name: Webhook deliveries
  - name: Incoming webhook payloads
paths:
  /imports:
    post:
      tags:
        - Imports
      summary: Import contacts into a list
      description: >-
        Queue a batch of contacts for creation or update and attach successful
        rows to an existing list. Requires `contacts:write` and `lists:write`.
        Supply a visible `listId`, an allowed current workspace `ownerId`, and
        1–10,000 rows. The parsed request, serialized as JSON, is limited to
        10,000,000 UTF-16 code units; this is not a byte-exact file-upload
        limit. The job owner overrides owner values inside rows.


        HTTP `202` returns an import ID, state and processed count. It means
        accepted for background work, not that every row is valid or complete.
        Rows use the contact write shape; stable external IDs update existing
        visible contacts. Poll the import with the same credential and inspect
        every row result.


        Persist an `Idempotency-Key`; retry the identical submission after an
        uncertain response to recover the same job. `413 import_too_large`
        requires smaller batches; `404 not_found` means the list is missing or
        inaccessible. Correct `403 invalid_owner` before submitting a new
        logical import.


        See [asynchronous imports](/guides/contact-lists#asynchronous-imports).
      operationId: postImports
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            pattern: ^[A-Za-z0-9._:-]{1,200}$
          description: >-
            Persist one key for this logical operation before sending it. Reuse
            the same value only with the same method, path and body after a
            timeout. A changed request returns 409 idempotency_conflict; a
            matching retry returns the original response.
          example: 9d6b623c-c132-4d2f-b8cf-7c65d4760dbe
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportWrite'
            example:
              listId: 456
              ownerId: user_example
              rows:
                - externalId: crm-contact-123
                  name: Alex Morgan
                  phoneNumber: '+12125550100'
                  timeZone: America/New_York
                  timeZoneSource: provided
      responses:
        '202':
          description: >-
            The import was queued. Use the returned ID to poll progress;
            row-level success is not yet established.
          headers:
            X-Request-Id:
              schema:
                type: string
                format: uuid
            RateLimit-Limit:
              schema:
                type: integer
            RateLimit-Remaining:
              schema:
                type: integer
            Idempotency-Replayed:
              schema:
                type: string
                enum:
                  - 'true'
                  - 'false'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportAccepted'
              example:
                id: 00000000-0000-4000-8000-000000000001
                state: pending
                processed: 0
        default:
          description: >-
            Error. 400 invalid request; 401 invalid credential; 403 insufficient
            access; 404 not found; 409 state/idempotency conflict; 413 size
            limit; 422 verification failure; 429 rate limit (Retry-After
            seconds); 503 temporary service failure.
          headers:
            Retry-After:
              schema:
                type: integer
            X-Request-Id:
              schema:
                type: string
                format: uuid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: invalid_api_key
                  message: API key is invalid, expired or revoked
                  requestId: 00000000-0000-4000-8000-000000000004
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            # Replace example resource IDs and ownerId with values from your
            workspace.

            : "${POWERDIALER_API_KEY:?Set POWERDIALER_API_KEY to your scoped API
            key}"

            # Set this once per operation; reuse it with the same request after
            a timeout.

            : "${POWERDIALER_REQUEST_ID:?Set POWERDIALER_REQUEST_ID to a new
            UUID for this operation}"

            curl --request POST \
              --url 'https://api.migration.powerdialer.ai/api/public/v2/imports' \
              --header "Authorization: Bearer $POWERDIALER_API_KEY" \
              --header "Idempotency-Key: $POWERDIALER_REQUEST_ID" \
              --header 'Content-Type: application/json' \
              --data '{
              "listId": 456,
              "ownerId": "user_example",
              "rows": [
                {
                  "externalId": "crm-contact-123",
                  "name": "Alex Morgan",
                  "phoneNumber": "+12125550100",
                  "timeZone": "America/New_York",
                  "timeZoneSource": "provided"
                }
              ]
            }'
components:
  schemas:
    ImportWrite:
      type: object
      properties:
        listId:
          type: integer
          minimum: 1
          maximum: 2147483647
          description: Existing calling list to receive successfully imported contacts.
        ownerId:
          type: string
          minLength: 1
          maxLength: 100
          description: >-
            Active workspace member assigned to every row. Overrides any ownerId
            supplied inside a row.
        rows:
          type: array
          items: {}
          minItems: 1
          maxItems: 10000
          description: >-
            Between 1 and 10,000 contact objects. Each row uses ContactWrite
            fields except that ownerId comes from the job. Invalid rows are
            reported separately during processing.
      required:
        - listId
        - ownerId
        - rows
      additionalProperties: false
      description: >-
        Accepts 1–10,000 rows for background processing. The serialized parsed
        request is limited to 10,000,000 UTF-16 code units (JavaScript string
        length). Rows are validated individually, using the job ownerId.
      examples:
        - listId: 456
          ownerId: user_example
          rows:
            - externalId: crm-contact-123
              name: Alex Morgan
              phoneNumber: '+12125550100'
              timeZone: America/New_York
              timeZoneSource: provided
    ImportAccepted:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Import job ID. Poll GET /imports/{id} with the same API key.
        state:
          type: string
          enum:
            - pending
          description: >-
            A newly accepted job starts as pending. Acceptance does not mean the
            contacts have been imported.
        processed:
          type: integer
          description: Number of rows processed so far; zero in the initial response.
      required:
        - id
        - state
        - processed
      examples:
        - id: 00000000-0000-4000-8000-000000000001
          state: pending
          processed: 0
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable machine-readable error code.
            message:
              type: string
              description: Human-readable explanation.
            requestId:
              type: string
              format: uuid
              description: Request identifier to include when investigating a failure.
            details:
              type: array
              items:
                type: object
                properties:
                  path:
                    type: string
                  message:
                    type: string
                required:
                  - path
                  - message
              description: Validation errors, when available.
          required:
            - code
            - message
            - requestId
      required:
        - error
      examples:
        - error:
            code: insufficient_scope
            message: Requires contacts:read
            requestId: 00000000-0000-4000-8000-000000000004
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      bearerFormat: pd_<live|test>_<credential UUID>.<random secret>
      description: >-
        Issued in Developers. Workspace/owner/scopes come from credential, never
        acting-user headers. API keys cannot manage API credentials.

````

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