From ff88654b258f1fa0b2c8021ffe36b21e6782c8b5 Mon Sep 17 00:00:00 2001 From: Varshini Suresh Date: Fri, 3 Jul 2026 00:35:37 +0100 Subject: [PATCH 1/3] Document bulk create and bulk delete contacts (Preview) Adds POST /contacts/bulk (strict create) and POST /contacts/bulk/delete (permanent delete), mirroring the existing bulk update endpoint. Co-Authored-By: Claude Sonnet 5 --- descriptions/0/api.intercom.io.yaml | 291 ++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) diff --git a/descriptions/0/api.intercom.io.yaml b/descriptions/0/api.intercom.io.yaml index 5cfe8e9..2dd9a7a 100644 --- a/descriptions/0/api.intercom.io.yaml +++ b/descriptions/0/api.intercom.io.yaml @@ -9088,6 +9088,107 @@ paths: schema: "$ref": "#/components/schemas/error" "/contacts/bulk": + post: + summary: Bulk create contacts + parameters: + - name: Intercom-Version + in: header + schema: + "$ref": "#/components/schemas/intercom_version" + tags: + - Contacts + operationId: BulkCreateContacts + description: | + You can bulk create contacts by submitting an array of contact objects. This is a **strict create** — it mirrors [Create a contact](/docs/references/preview/rest-api/api.intercom.io/contacts/createcontact) and never updates an existing contact. + + The endpoint creates an async job that processes the items in the background. Use the returned job ID with `GET /contacts/bulk/{id}` to check the job status. + + {% admonition type="info" name="Handling existing contacts" %} + If a contact already exists with the given `external_id` or `email` (including an archived contact), that item is rejected and the job's `state` ends as `completed_with_errors`. Genuinely new contacts in the same request are still created. There's currently no per-item error detail — the job `state` from `GET /contacts/bulk/{id}` is the only signal that one or more items were rejected. + + Created contacts aren't returned with IDs in the response. Look them up afterwards with [Get a contact by External ID](/docs/references/preview/rest-api/api.intercom.io/contacts/getcontactbyexternalid) or [Search contacts](/docs/references/preview/rest-api/api.intercom.io/contacts/searchcontacts). + {% /admonition %} + + {% admonition type="info" name="Limits" %} + - Maximum of 100 contacts per request. + - You can append tasks to an existing job by including `job.id` in the request body. + {% /admonition %} + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/bulk_create_contacts_request" + examples: + successful: + summary: Successful + value: + contacts: + - external_id: abc123 + email: joe@bloggs.com + name: Joe Bloggs + - external_id: def456 + email: maria@example.com + name: "María García" + role: lead + responses: + '202': + description: Accepted + content: + application/json: + examples: + successful: + value: + id: job_v2_2 + type: contacts.bulk.job + state: running + created_at: 1713360000 + updated_at: 1713360060 + completed_at: + tasks: + - id: task_v2_2 + item_count: 2 + state: pending + created_at: 1713360000 + started_at: + completed_at: + url: https://api.intercom.io/contacts/bulk/job_v2_2 + schema: + "$ref": "#/components/schemas/contacts_bulk_job" + '401': + description: Unauthorized + content: + application/json: + examples: + Unauthorized: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: unauthorized + message: Access Token Invalid + schema: + "$ref": "#/components/schemas/error" + '422': + description: Unprocessable Entity + content: + application/json: + examples: + missing_contacts: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: missing_field + message: contacts field must be supplied + too_many_contacts: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: invalid_parameter + message: maximum number of contacts per request is 100 + schema: + "$ref": "#/components/schemas/error" put: summary: Bulk update contacts parameters: @@ -9270,6 +9371,108 @@ paths: message: Access Token Invalid schema: "$ref": "#/components/schemas/error" + "/contacts/bulk/delete": + post: + summary: Bulk delete contacts + parameters: + - name: Intercom-Version + in: header + schema: + "$ref": "#/components/schemas/intercom_version" + tags: + - Contacts + operationId: BulkDeleteContacts + description: | + You can permanently delete contacts in bulk by submitting an array of contact `id`s. This mirrors [Delete a contact](/docs/references/preview/rest-api/api.intercom.io/contacts/deletecontact) — deleted contacts are **not restorable**. + + The endpoint creates an async job that processes the deletes in the background. Use the returned job ID with `GET /contacts/bulk/{id}` to check the job status. + + {% admonition type="warning" name="Permanent deletion" %} + Unlike archiving, permanently deleted contacts cannot be recovered. A contact that doesn't exist, or can't be deleted, fails that item and the job's `state` ends as `completed_with_errors` (visible via `GET /contacts/bulk/{id}`) without failing the rest of the batch. Contacts with a `visitor` role are silently skipped rather than counted as failures. + {% /admonition %} + + {% admonition type="info" name="Limits" %} + - Maximum of 100 contacts per request. + - You can append tasks to an existing job by including `job.id` in the request body. + {% /admonition %} + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/bulk_delete_contacts_request" + examples: + successful: + summary: Successful + value: + contacts: + - id: abc123 + - id: def456 + responses: + '202': + description: Accepted + content: + application/json: + examples: + successful: + value: + id: job_v2_3 + type: contacts.bulk.job + state: running + created_at: 1713360000 + updated_at: 1713360060 + completed_at: + tasks: + - id: task_v2_3 + item_count: 2 + state: pending + created_at: 1713360000 + started_at: + completed_at: + url: https://api.intercom.io/contacts/bulk/job_v2_3 + schema: + "$ref": "#/components/schemas/contacts_bulk_job" + '401': + description: Unauthorized + content: + application/json: + examples: + Unauthorized: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: unauthorized + message: Access Token Invalid + schema: + "$ref": "#/components/schemas/error" + '422': + description: Unprocessable Entity + content: + application/json: + examples: + missing_contacts: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: missing_field + message: contacts field must be supplied + missing_id: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: missing_field + message: contacts must be identified by id + too_many_contacts: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: invalid_parameter + message: maximum number of contacts per request is 100 + schema: + "$ref": "#/components/schemas/error" "/content/bulk_actions": post: summary: Run a bulk action on Knowledge Hub content (Preview) @@ -26719,6 +26922,94 @@ components: type: array items: $ref: "#/components/schemas/brand" + bulk_create_contacts_request: + title: Bulk Create Contacts Request + type: object + description: Request body for bulk creating contacts. + required: + - contacts + properties: + contacts: + type: array + description: An array of contact objects to create. Maximum 100 contacts + per request. + maxItems: 100 + items: + type: object + properties: + external_id: + type: string + description: A unique identifier for the contact which you have + defined. + example: abc123 + email: + type: string + description: The contact's email address. + example: joe@example.com + name: + type: string + description: The contact's name. + example: Joe Bloggs + role: + type: string + description: The contact's role. One of `user` or `lead`. Leads + are exempt from the uniqueness check described above. + example: user + phone: + type: string + description: The contact's phone number. + language_override: + type: string + description: A preferred language setting for the contact, used by + the Intercom Messenger. + example: fr + custom_attributes: + type: object + description: Custom attributes to set on the contact. + signed_up_at: + type: integer + description: The time the contact signed up, in Unix timestamp format. + last_seen_at: + type: integer + description: The time the contact was last seen, in Unix timestamp + format. + job: + type: object + description: Optional. Include to append tasks to an existing job. + properties: + id: + type: string + description: The ID of an existing bulk job to append to. + example: job_v2_1 + bulk_delete_contacts_request: + title: Bulk Delete Contacts Request + type: object + description: Request body for permanently bulk deleting contacts. + required: + - contacts + properties: + contacts: + type: array + description: An array of contacts to delete, each identified by `id`. + Maximum 100 contacts per request. + maxItems: 100 + items: + type: object + required: + - id + properties: + id: + type: string + description: The unique identifier for the contact. + example: abc123 + job: + type: object + description: Optional. Include to append tasks to an existing job. + properties: + id: + type: string + description: The ID of an existing bulk job to append to. + example: job_v2_1 bulk_update_contacts_request: title: Bulk Update Contacts Request type: object From 66488e7b79eae2a73809da6d50dcb268dd2f343f Mon Sep 17 00:00:00 2001 From: Varshini Suresh Date: Fri, 3 Jul 2026 22:25:06 +0100 Subject: [PATCH 2/3] Align bulk contact create/update fields with the single contact endpoints Adds avatar, owner_id, unsubscribed_from_emails, and tags (add/remove) to bulk create/update request bodies to match the single contact create/update endpoints. Renames the update identifier field to external_id and owner_id to string to match the rest of the contact schemas, drops the undocumented companies/company properties, and clarifies tag id requirements and best-effort application behavior. --- descriptions/0/api.intercom.io.yaml | 76 ++++++++++++++++------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/descriptions/0/api.intercom.io.yaml b/descriptions/0/api.intercom.io.yaml index 2dd9a7a..317dc37 100644 --- a/descriptions/0/api.intercom.io.yaml +++ b/descriptions/0/api.intercom.io.yaml @@ -26958,6 +26958,10 @@ components: phone: type: string description: The contact's phone number. + avatar: + type: string + description: An image URL containing the avatar of the contact. + example: https://www.example.com/avatar_image.jpg language_override: type: string description: A preferred language setting for the contact, used by @@ -26973,6 +26977,32 @@ components: type: integer description: The time the contact was last seen, in Unix timestamp format. + owner_id: + type: string + description: The ID of an admin that has been assigned account ownership + of the contact. + example: "321" + unsubscribed_from_emails: + type: boolean + description: Whether the contact is unsubscribed from emails. + example: true + tags: + type: object + description: | + Tags to add to the contact. Each tag is identified by its `id`, which must be a positive integer for a tag that already exists in your workspace. Tag application is best-effort: unknown tag IDs are skipped while the rest of the contact create still applies. Per-tag results are not yet returned in the job status. + properties: + add: + type: array + description: Tags to add to the contact. + items: + type: object + required: + - id + properties: + id: + type: string + description: The ID of an existing tag to add to the contact. + example: '123' job: type: object description: Optional. Include to append tasks to an existing job. @@ -27044,55 +27074,31 @@ components: description: A preferred language setting for the contact, used by the Intercom Messenger. example: fr - user_id: + external_id: type: string - description: A unique identifier for the contact that you provide. Maps to the contact's external user ID. - example: '25' + description: A unique identifier for the contact which you have + defined. + example: abc123 phone: type: string description: The contact's phone number. example: "+353871234567" owner_id: - type: integer - description: The ID of the teammate who owns the contact. - example: 123 + type: string + description: The ID of an admin that has been assigned account ownership + of the contact. + example: "321" unsubscribed_from_emails: type: boolean description: Whether the contact is unsubscribed from emails. example: true avatar: type: string - description: An image URL for the contact's avatar. You can also pass an object with an `image_url` field. - example: https://www.example.com/avatar.png + description: An image URL containing the avatar of the contact. + example: https://www.example.com/avatar_image.jpg custom_attributes: type: object description: Custom attributes to update on the contact. - companies: - type: array - description: A list of companies to associate with the contact. Each company is identified by the `company_id` you have defined. Companies that do not exist are created. - items: - type: object - properties: - company_id: - type: string - description: The company ID you have defined for the company. - example: '6' - name: - type: string - description: The name of the company. - example: Blue Sun - company: - type: object - description: A single company to associate with the contact, identified by the `company_id` you have defined. Created if it does not exist. - properties: - company_id: - type: string - description: The company ID you have defined for the company. - example: '6' - name: - type: string - description: The name of the company. - example: Blue Sun tags: type: object description: | @@ -27121,7 +27127,7 @@ components: id: type: string description: The ID of an existing tag to remove from the contact. - example: '456' + example: '789' job: type: object description: Optional. Include to append tasks to an existing job. From ee3421034bb75c88c3bc4ec74bd29ef5b0efa0da Mon Sep 17 00:00:00 2001 From: Varshini Suresh Date: Mon, 6 Jul 2026 15:46:26 +0100 Subject: [PATCH 3/3] Match Preview bulk contacts spec to developer-docs (source of truth) Align the bulk create/update/delete contact sections with developer-docs PR #1018: trim endpoint descriptions, drop the phone example and reorder bulk_update fields, and move /contacts/bulk/delete ahead of /contacts/bulk/{id}. Sections are now byte-identical to the docs source of truth. Co-Authored-By: Claude Opus 4.8 (1M context) --- descriptions/0/api.intercom.io.yaml | 151 ++++++++++++++-------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/descriptions/0/api.intercom.io.yaml b/descriptions/0/api.intercom.io.yaml index 317dc37..fa2d522 100644 --- a/descriptions/0/api.intercom.io.yaml +++ b/descriptions/0/api.intercom.io.yaml @@ -9099,12 +9099,12 @@ paths: - Contacts operationId: BulkCreateContacts description: | - You can bulk create contacts by submitting an array of contact objects. This is a **strict create** — it mirrors [Create a contact](/docs/references/preview/rest-api/api.intercom.io/contacts/createcontact) and never updates an existing contact. + You can bulk create contacts by submitting an array of contact objects. This is a **strict create** and never updates an existing contact. The endpoint creates an async job that processes the items in the background. Use the returned job ID with `GET /contacts/bulk/{id}` to check the job status. {% admonition type="info" name="Handling existing contacts" %} - If a contact already exists with the given `external_id` or `email` (including an archived contact), that item is rejected and the job's `state` ends as `completed_with_errors`. Genuinely new contacts in the same request are still created. There's currently no per-item error detail — the job `state` from `GET /contacts/bulk/{id}` is the only signal that one or more items were rejected. + If a contact already exists with the given `external_id` or `email` (including an archived contact), that item is rejected and the job's `state` ends as `completed_with_errors`. New contacts in the same request are still created. The job `state` from `GET /contacts/bulk/{id}` is the signal that one or more items were rejected. Created contacts aren't returned with IDs in the response. Look them up afterwards with [Get a contact by External ID](/docs/references/preview/rest-api/api.intercom.io/contacts/getcontactbyexternalid) or [Search contacts](/docs/references/preview/rest-api/api.intercom.io/contacts/searchcontacts). {% /admonition %} @@ -9313,64 +9313,6 @@ paths: message: maximum number of contacts per request is 100 schema: "$ref": "#/components/schemas/error" - "/contacts/bulk/{id}": - get: - summary: Get a bulk update job - parameters: - - name: Intercom-Version - in: header - schema: - "$ref": "#/components/schemas/intercom_version" - - name: id - in: path - description: The unique identifier for the bulk job. - example: job_v2_1 - required: true - schema: - type: string - tags: - - Contacts - operationId: ShowBulkUpdateContactsJob - description: | - You can check the status of a bulk contact update job. The `state` field indicates the overall job progress: `pending`, `running`, `completed`, or `completed_with_errors`. - responses: - '200': - description: successful - content: - application/json: - examples: - successful: - value: - id: job_v2_1 - type: contacts.bulk.job - state: completed - created_at: 1713360000 - updated_at: 1713360120 - completed_at: 1713360120 - tasks: - - id: task_v2_1 - item_count: 3 - state: completed - created_at: 1713360000 - started_at: 1713360060 - completed_at: 1713360120 - url: https://api.intercom.io/contacts/bulk/job_v2_1 - schema: - "$ref": "#/components/schemas/contacts_bulk_job" - '401': - description: Unauthorized - content: - application/json: - examples: - Unauthorized: - value: - type: error.list - request_id: 2859da57-c83f-405c-8166-240a312442a3 - errors: - - code: unauthorized - message: Access Token Invalid - schema: - "$ref": "#/components/schemas/error" "/contacts/bulk/delete": post: summary: Bulk delete contacts @@ -9383,12 +9325,12 @@ paths: - Contacts operationId: BulkDeleteContacts description: | - You can permanently delete contacts in bulk by submitting an array of contact `id`s. This mirrors [Delete a contact](/docs/references/preview/rest-api/api.intercom.io/contacts/deletecontact) — deleted contacts are **not restorable**. + You can permanently delete contacts in bulk by submitting an array of contact `id`s. The endpoint creates an async job that processes the deletes in the background. Use the returned job ID with `GET /contacts/bulk/{id}` to check the job status. {% admonition type="warning" name="Permanent deletion" %} - Unlike archiving, permanently deleted contacts cannot be recovered. A contact that doesn't exist, or can't be deleted, fails that item and the job's `state` ends as `completed_with_errors` (visible via `GET /contacts/bulk/{id}`) without failing the rest of the batch. Contacts with a `visitor` role are silently skipped rather than counted as failures. + A contact that doesn't exist, or can't be deleted, fails that item and the job's `state` ends as `completed_with_errors` (visible via `GET /contacts/bulk/{id}`) without failing the rest of the batch. {% /admonition %} {% admonition type="info" name="Limits" %} @@ -9473,6 +9415,64 @@ paths: message: maximum number of contacts per request is 100 schema: "$ref": "#/components/schemas/error" + "/contacts/bulk/{id}": + get: + summary: Get a bulk update job + parameters: + - name: Intercom-Version + in: header + schema: + "$ref": "#/components/schemas/intercom_version" + - name: id + in: path + description: The unique identifier for the bulk job. + example: job_v2_1 + required: true + schema: + type: string + tags: + - Contacts + operationId: ShowBulkUpdateContactsJob + description: | + You can check the status of a bulk contact update job. The `state` field indicates the overall job progress: `pending`, `running`, `completed`, or `completed_with_errors`. + responses: + '200': + description: successful + content: + application/json: + examples: + successful: + value: + id: job_v2_1 + type: contacts.bulk.job + state: completed + created_at: 1713360000 + updated_at: 1713360120 + completed_at: 1713360120 + tasks: + - id: task_v2_1 + item_count: 3 + state: completed + created_at: 1713360000 + started_at: 1713360060 + completed_at: 1713360120 + url: https://api.intercom.io/contacts/bulk/job_v2_1 + schema: + "$ref": "#/components/schemas/contacts_bulk_job" + '401': + description: Unauthorized + content: + application/json: + examples: + Unauthorized: + value: + type: error.list + request_id: 2859da57-c83f-405c-8166-240a312442a3 + errors: + - code: unauthorized + message: Access Token Invalid + schema: + "$ref": "#/components/schemas/error" "/content/bulk_actions": post: summary: Run a bulk action on Knowledge Hub content (Preview) @@ -27061,6 +27061,11 @@ components: type: string description: The unique identifier for the contact. example: abc123 + external_id: + type: string + description: A unique identifier for the contact which you have + defined. + example: abc123 email: type: string description: The contact's email address. @@ -27069,20 +27074,13 @@ components: type: string description: The contact's name. example: Joe Bloggs - language_override: - type: string - description: A preferred language setting for the contact, used by - the Intercom Messenger. - example: fr - external_id: - type: string - description: A unique identifier for the contact which you have - defined. - example: abc123 phone: type: string description: The contact's phone number. - example: "+353871234567" + avatar: + type: string + description: An image URL containing the avatar of the contact. + example: https://www.example.com/avatar_image.jpg owner_id: type: string description: The ID of an admin that has been assigned account ownership @@ -27092,10 +27090,11 @@ components: type: boolean description: Whether the contact is unsubscribed from emails. example: true - avatar: + language_override: type: string - description: An image URL containing the avatar of the contact. - example: https://www.example.com/avatar_image.jpg + description: A preferred language setting for the contact, used by + the Intercom Messenger. + example: fr custom_attributes: type: object description: Custom attributes to update on the contact.