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

# Update a contact

> Replace the writable details of a known contact while preserving its PowerDialer ID. Requires `contacts:write`. The existing contact and requested `ownerId` must both be permitted by the credential, and the new owner must be a current workspace member.

Send the full contact write shape, including owner and phone number. This is not a partial PATCH: omitted name, additional numbers, metadata and timezone fields take their documented defaults. An omitted `externalId` preserves the existing value; providing one changes the contact's external mapping. Keep external IDs unique within the workspace. Updating a contact does not move its calling-list memberships.

Use a persisted `Idempotency-Key`; retry an uncertain response with the identical request. `404 not_found` means the contact is missing or outside scope. For `403 invalid_owner`, choose an allowed member. `409 idempotency_conflict` requires the original request or a new key for a genuinely different operation.

See [contact write semantics](/guides/contact-lists#create-or-update-a-contact).



## OpenAPI

````yaml /api/openapi.json put /contacts/{id}
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:
  /contacts/{id}:
    put:
      tags:
        - Contacts
      summary: Update a contact
      description: >-
        Replace the writable details of a known contact while preserving its
        PowerDialer ID. Requires `contacts:write`. The existing contact and
        requested `ownerId` must both be permitted by the credential, and the
        new owner must be a current workspace member.


        Send the full contact write shape, including owner and phone number.
        This is not a partial PATCH: omitted name, additional numbers, metadata
        and timezone fields take their documented defaults. An omitted
        `externalId` preserves the existing value; providing one changes the
        contact's external mapping. Keep external IDs unique within the
        workspace. Updating a contact does not move its calling-list
        memberships.


        Use a persisted `Idempotency-Key`; retry an uncertain response with the
        identical request. `404 not_found` means the contact is missing or
        outside scope. For `403 invalid_owner`, choose an allowed member. `409
        idempotency_conflict` requires the original request or a new key for a
        genuinely different operation.


        See [contact write
        semantics](/guides/contact-lists#create-or-update-a-contact).
      operationId: putContactsById
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 2147483647
          description: >-
            Numeric PowerDialer contact ID, not your CRM externalId. The contact
            must be inside the credential’s workspace and owner scope.
          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
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactWrite'
            example:
              ownerId: user_example
              externalId: crm-contact-123
              name: Alex Morgan
              phoneNumber: '+12125550100'
              additionalNumbers: []
              metadata:
                source: website
              timeZone: America/New_York
              timeZoneSource: provided
      responses:
        '200':
          description: The updated contact, or the saved response for an identical retry.
          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/Contact'
              example:
                ownerId: user_example
                externalId: crm-contact-123
                name: Alex Morgan
                phoneNumber: '+12125550100'
                additionalNumbers: []
                metadata:
                  source: website
                  timeZone: America/New_York
                  timeZoneSource: provided
                timeZone: America/New_York
                timeZoneSource: provided
                id: 123
                createdAt: '2026-10-08T12:00:00.000Z'
                updatedAt: '2026-10-08T12:00:00.000Z'
        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/contacts/123' \
              --header "Authorization: Bearer $POWERDIALER_API_KEY" \
              --header "Idempotency-Key: $POWERDIALER_REQUEST_ID" \
              --header 'Content-Type: application/json' \
              --data '{
              "ownerId": "user_example",
              "externalId": "crm-contact-123",
              "name": "Alex Morgan",
              "phoneNumber": "+12125550100",
              "additionalNumbers": [],
              "metadata": {
                "source": "website"
              },
              "timeZone": "America/New_York",
              "timeZoneSource": "provided"
            }'
components:
  schemas:
    ContactWrite:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            Stable contact ID from your CRM or source system, unique within this
            workspace. Reuse it on POST to update an existing contact.
        ownerId:
          type: string
          minLength: 1
          maxLength: 100
          description: >-
            ID of an active PowerDialer workspace member allowed by this key.
            Personal keys must use their own ownerId from GET /me.
        name:
          type: string
          maxLength: 500
          default: ''
          description: >-
            Contact display name. Omitting this field on a write resets it to an
            empty string.
        phoneNumber:
          type: string
          pattern: ^\+[1-9]\d{6,14}$
          description: Primary number in E.164 format, including + and country code.
        additionalNumbers:
          type: array
          items:
            type: string
            pattern: ^\+[1-9]\d{6,14}$
          maxItems: 10
          default: []
          description: >-
            Up to 10 additional E.164 numbers. Replaces the stored array;
            omitted means empty.
        metadata:
          type: object
          additionalProperties: true
          default: {}
          description: >-
            Your JSON object. Its JSON.stringify output must fit within 16,000
            UTF-16 code units. Replaces existing metadata. Top-level timezone
            fields overwrite the matching metadata keys.
        timeZone:
          anyOf:
            - type: string
              maxLength: 100
            - type: 'null'
          default: null
          description: >-
            IANA timezone such as America/New_York. A non-null value requires
            timeZoneSource provided or phone_estimate; null or omission requires
            unknown. The API does not infer a timezone.
        timeZoneSource:
          type: string
          enum:
            - provided
            - phone_estimate
            - unknown
          default: unknown
          description: >-
            provided for a known timezone, phone_estimate for an estimate made
            by your integration, or unknown when timeZone is null.
      required:
        - ownerId
        - phoneNumber
      additionalProperties: false
      examples:
        - ownerId: user_example
          externalId: crm-contact-123
          name: Alex Morgan
          phoneNumber: '+12125550100'
          additionalNumbers: []
          metadata:
            source: website
          timeZone: America/New_York
          timeZoneSource: provided
    Contact:
      type: object
      properties:
        id:
          type: integer
          description: PowerDialer contact ID. Use this integer in contact URLs.
        name:
          type: string
          description: Stored contact name.
        phoneNumber:
          type: string
          description: Stored primary phone number. V2 writes require E.164.
        additionalNumbers:
          type: array
          items:
            type: string
          description: Stored additional phone numbers.
        metadata:
          description: >-
            Stored JSON metadata. v2 writes use objects; legacy rows may contain
            other JSON values.
        ownerId:
          anyOf:
            - type: string
            - type: 'null'
          description: Attributed PowerDialer member ID.
        externalId:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Your source-system identifier, or null when no identifier was
            assigned.
        createdAt:
          type: string
          format: date-time
          description: Time the contact was created, in UTC.
        updatedAt:
          type: string
          format: date-time
          description: Time the contact was last updated, in UTC.
        timeZone:
          description: >-
            Stored timezone metadata. V2 writes produce an IANA string or null;
            legacy metadata may contain another JSON value.
        timeZoneSource:
          description: >-
            Stored timezone-source metadata. V2 writes use provided,
            phone_estimate, or unknown; legacy values may differ.
      required:
        - id
        - name
        - phoneNumber
        - additionalNumbers
        - metadata
        - ownerId
        - externalId
        - createdAt
        - updatedAt
        - timeZone
        - timeZoneSource
      examples:
        - ownerId: user_example
          externalId: crm-contact-123
          name: Alex Morgan
          phoneNumber: '+12125550100'
          additionalNumbers: []
          metadata:
            source: website
            timeZone: America/New_York
            timeZoneSource: provided
          timeZone: America/New_York
          timeZoneSource: provided
          id: 123
          createdAt: '2026-10-08T12:00:00.000Z'
          updatedAt: '2026-10-08T12:00:00.000Z'
    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.