Skip to content

Align the 2.17 and Preview contacts endpoints with what the API sends and accepts - #751

Merged
markdennis22 merged 8 commits into
mainfrom
markdennis/2-17-contacts-align
Oct 22, 2026
Merged

markdennis22 merged 8 commits into
mainfrom
markdennis/2-17-contacts-align

Conversation

@markdennis22

@markdennis22 markdennis22 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Why?

The 2.17 spec for the contacts endpoints didn't match what the API sends and accepts. It was missing fields, parameters and error responses, typed avatar as an object when the API returns a URL string, and listed search fields that don't exist. The Preview spec had the same problems, and the next version is cut from Preview, so it needs the same fixes.

How?

Corrects the contacts endpoints and contact schemas to match the API's current behaviour, and adds the OAuth scopes each endpoint accepts to its description. The same changes go into the Preview spec, keeping content that only applies to Preview, such as user-to-user merge.

Risks

The Preview SDKs are generated from this spec, so these changes affect generated Preview types:

Change Could SDK code stop compiling? Did that code work before?
Contact.avatar becomes a string, and the ContactAvatar type is removed Yes, if it reads avatar.image_url No. The API sends a string
ContactAttachedCompanies.companies is renamed to data Yes, if it reads companies No. The API sends data
ContactsBulkJobState loses pending Yes, if it matches on pending No. A job is never pending
The Show, Show by external ID, Create, Update and Merge contact response types stop extending Contact, with the same fields In Java and Python, code that passes one where a Contact is expected. TypeScript is unaffected Yes
New optional fields on Contact, ContactLocation and ContactSubscriptionTypes, a new order enum, and consent_type no longer required No —
Notes for reviewers
  • The extends change happens because contact now lists enabled_push_messaging, which those five responses also declare inline, and the generator flattens any schema that redeclares a parent property.
  • fern check shows 0 errors and the same 317 warnings as main. There are no new dangling refs, and the operations are unchanged.

Generated with Claude Code

Adds the fields, parameters and error responses the contacts endpoints
use but the spec left out, corrects the search field and operator
tables and the avatar type, and adds the OAuth scopes each endpoint
accepts to its description.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@markdennis22
markdennis22 marked this pull request as ready for review October 21, 2026 16:10

@cathalging cathalging left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this checks out against how the API behaves. Three things to fix:

  1. Search contacts (2.17 L10466): each IN/NIN value counts as a condition in its group, so the 15-per-group limit applies first. A request with 16 to 50 values gets a 400 "Number of elements in composite query is greater than 15…" rather than reaching the 50-value limit. Suggest documenting 15.
  2. contact.email_verified (2.17 L29817): List contacts and Search contacts do return this field at 2.17, so "Not included in List contacts or Search contacts responses" should go.
  3. Preview (descriptions/0) still has the old text, so the next version cut would undo these fixes. A linked Preview change is needed. Since Preview feeds the SDK, avatar object → string, companies → data, dropping pending and the activity fields losing nullable will be breaking SDK changes.

~ Automated via Claude (about: https://github.com/intercom/claude-plugins/blob/main/plugins/base/docs/external-message-attribution.md)

Adds the token_unauthorized example to each contacts endpoint's 401 response.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. It's careful work. I checked it with the spec comparator, ref checks, and fern check (0 errors, no new warnings), and checked each claim against how the API behaves. avatar, data, bulk job state, the omitted activity fields, consent_type, the documented bugs and the scope lines are confirmed.

A few questions:

  1. email_verified "Not included in List contacts or Search contacts responses" — At 2.17, List and Search do return email_verified for each contact. It's only left out in the rare case the contact can't be loaded, for example when it's deleted mid-request. Could the description say that instead?
  2. Preview merge duplicate check — It's right that external ID is never compared. But the phone check also matches the source's phone against the target's WhatsApp number. Should the description say "email or phone (including the target's WhatsApp number)"?
  3. escape_identity on /contacts/deleted — That description says it escapes email only, while the other four say name and email. Should they all match?
  4. Breaking 2.17 changes — The PR body covers them well: avatar, companies → data, pending, and the six nullables. Since 2.17 is released, could someone who owns the public contract sign off on these before merge?

Holding approval for item 1 and the sign-off in item 4.

~ Automated via Claude

markdennis22 and others added 6 commits October 22, 2026 09:49
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…d the merge preview phone match

Each IN or NIN value counts toward the 15-condition group limit, so 15 is the effective cap. List and search contacts do return email_verified. The merge preview duplicate check also matches the source phone against the destination WhatsApp number.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…conflict errors

The detach response re-reads the company after the contact is removed, so
its user_count already excludes the contact. Also documents the user-to-lead
400 on update, the two other create 409s, the 15-condition search error, and
how per_page, starting_after, order and escape_identity really behave.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…search fields

The multiple-match 409 on create only happens when no external_id is sent,
so its message has nothing after id=. referrer is overwritten whenever the
Messenger reports one, so it isn't the first-seen page. The ios_* and
android_* search fields also become searchable once the SDK is set up in
the workspace, before any request from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Applies the 2.17 Contacts changes from #751 to the Preview spec, merged
operation by operation so Preview-only content is kept: user-to-user merge
and its merge_users scope, the fuller language_override description, and
whatsapp_number. The email_verified note no longer says the field is
Preview-only, since 2.17 returns it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…search fields in Preview

The multiple-match 409 on create only happens when no external_id is sent,
so its message has nothing after id=. referrer is overwritten whenever the
Messenger reports one, so it isn't the first-seen page. The ios_* and
android_* search fields also become searchable once the SDK is set up in
the workspace, before any request from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@markdennis22 markdennis22 changed the title Align the 2.17 contacts endpoints with what the API sends and accepts Align the 2.17 and Preview contacts endpoints with what the API sends and accepts Oct 22, 2026
@markdennis22
markdennis22 merged commit da66c0f into main Oct 22, 2026
4 checks passed
@markdennis22
markdennis22 deleted the markdennis/2-17-contacts-align branch October 22, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants