> ## 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.

# Add a contact to a list

> Attach an existing contact to a calling list without creating another contact record. Requires `lists:write` and `contacts:read`. Both the list and contact must be visible within the key's workspace and permitted owner scope; knowing their IDs alone does not grant access.

Use numeric PowerDialer IDs for both path parameters and send no request body. The response is `{listId,contactId,member:true}`. Contact fields and ownership remain unchanged. For a new lead, create or upsert the contact first; for many rows, consider an asynchronous import instead.

Persist an `Idempotency-Key` for the attachment and reuse the same request after a timeout. `404 not_found` can refer to either missing or inaccessible resource; check both IDs with permitted read endpoints. `403 insufficient_scope` requires both permissions. `409 idempotency_conflict` means the operation key was reused for another action.

See [membership operations](/guides/contact-lists#list-membership).



## OpenAPI

````yaml /api/openapi.json put /lists/{id}/contacts/{contactId}
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:
  /lists/{id}/contacts/{contactId}:
    put:
      tags:
        - Calling lists
      summary: Add a contact to a list
      description: >-
        Attach an existing contact to a calling list without creating another
        contact record. Requires `lists:write` and `contacts:read`. Both the
        list and contact must be visible within the key's workspace and
        permitted owner scope; knowing their IDs alone does not grant access.


        Use numeric PowerDialer IDs for both path parameters and send no request
        body. The response is `{listId,contactId,member:true}`. Contact fields
        and ownership remain unchanged. For a new lead, create or upsert the
        contact first; for many rows, consider an asynchronous import instead.


        Persist an `Idempotency-Key` for the attachment and reuse the same
        request after a timeout. `404 not_found` can refer to either missing or
        inaccessible resource; check both IDs with permitted read endpoints.
        `403 insufficient_scope` requires both permissions. `409
        idempotency_conflict` means the operation key was reused for another
        action.


        See [membership operations](/guides/contact-lists#list-membership).
      operationId: putListsByIdContactsByContactid
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 2147483647
          description: >-
            Numeric calling-list ID returned by POST /lists or GET /lists. The
            list must be visible to this credential.
          example: 456
        - name: contactId
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 2147483647
          description: >-
            Numeric PowerDialer contact ID from a contact read/write or import
            result. The contact must be visible to this credential.
          example: 123
        - 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
      responses:
        '200':
          description: >-
            The contact is a member of the list, or the original successful
            attachment response was replayed.
          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/Membership'
              example:
                listId: 456
                contactId: 123
                member: true
        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 PUT \
              --url 'https://api.migration.powerdialer.ai/api/public/v2/lists/456/contacts/123' \
              --header "Authorization: Bearer $POWERDIALER_API_KEY" \
              --header "Idempotency-Key: $POWERDIALER_REQUEST_ID"
components:
  schemas:
    Membership:
      type: object
      properties:
        listId:
          type: integer
          description: Calling-list ID.
        contactId:
          type: integer
          description: Contact ID.
        member:
          type: boolean
          description: True after adding membership; false after removing it.
      required:
        - listId
        - contactId
        - member
      examples:
        - listId: 456
          contactId: 123
          member: true
    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.