# 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/contacts' \
--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"
}'{
"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"
}{
"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": {
"code": "invalid_api_key",
"message": "API key is invalid, expired or revoked",
"requestId": "00000000-0000-4000-8000-000000000004"
}
}Create or update a contact
Send a contact from your CRM using an ID that stays stable across synchronizations. Requires contacts:write. With externalId, this request updates the matching contact in the workspace or creates one if no match exists. Without it, a new logical request creates a new contact; phone-number equality does not perform an upsert.
Supply an allowed current workspace member as ownerId, an E.164 number, and any contact details. The full write shape applies on updates: omitted defaulted fields reset. A non-null timezone requires provided or phone_estimate; null requires unknown. This request does not add list membership.
Persist an Idempotency-Key and reuse it with the same request after a timeout. Matching retries return the original status/body. 403 invalid_owner requires a permitted member; 409 external_id_conflict means the external ID belongs outside your owner scope. Correct 400 validation errors before sending a new operation.
See contact writes.
# 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/contacts' \
--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"
}'{
"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"
}{
"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": {
"code": "invalid_api_key",
"message": "API key is invalid, expired or revoked",
"requestId": "00000000-0000-4000-8000-000000000004"
}
}Authorizations
Issued in Developers. Workspace/owner/scopes come from credential, never acting-user headers. API keys cannot manage API credentials.
Headers
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.
^[A-Za-z0-9._:-]{1,200}$Body
ID of an active PowerDialer workspace member allowed by this key. Personal keys must use their own ownerId from GET /me.
1 - 100Primary number in E.164 format, including + and country code.
^\+[1-9]\d{6,14}$Stable contact ID from your CRM or source system, unique within this workspace. Reuse it on POST to update an existing contact.
1 - 200Contact display name. Omitting this field on a write resets it to an empty string.
500Up to 10 additional E.164 numbers. Replaces the stored array; omitted means empty.
10^\+[1-9]\d{6,14}$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.
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.
100provided for a known timezone, phone_estimate for an estimate made by your integration, or unknown when timeZone is null.
provided, phone_estimate, unknown Response
The existing contact was updated, or a successful update receipt was replayed.
PowerDialer contact ID. Use this integer in contact URLs.
Stored contact name.
Stored primary phone number. V2 writes require E.164.
Stored additional phone numbers.
Stored JSON metadata. v2 writes use objects; legacy rows may contain other JSON values.
Attributed PowerDialer member ID.
Your source-system identifier, or null when no identifier was assigned.
Time the contact was created, in UTC.
Time the contact was last updated, in UTC.
Stored timezone metadata. V2 writes produce an IANA string or null; legacy metadata may contain another JSON value.
Stored timezone-source metadata. V2 writes use provided, phone_estimate, or unknown; legacy values may differ.