Skip to content

fix: allow null contact first_name and last_name - #255

Draft
gabrielmfern wants to merge 1 commit into
mainfrom
feature/dev-1625-nullable-contact-names
Draft

fix: allow null contact first_name and last_name#255
gabrielmfern wants to merge 1 commit into
mainfrom
feature/dev-1625-nullable-contact-names

Conversation

@gabrielmfern

@gabrielmfern gabrielmfern commented Aug 17, 2026

Copy link
Copy Markdown
Member

The API returns null for a contact with no name, but both fields were typed NotRequired[str]. That is the wrong axis: NotRequired says the key may be absent, while still promising that if the key is there the value is a real str. null is precisely the case it ruled out, so a type checker would bless contact["first_name"].upper() on a value that is None at runtime.

resend-node's recorded live responses carry "first_name":null in 12 separate fixtures, so this is the normal shape for a contact with no name, not an edge case.

The two types differ on purpose

Contact (retrieve and list) → Optional[str]. The key is always present in real responses, carrying null when there is no name.

ContactEventData (webhook) → NotRequired[Optional[str]]. Here the key really can be missing. The contact.created fixture in resend-dotnet omits first_name and last_name from data entirely, and the OpenAPI schema's required list agrees, covering only id, created_at, updated_at, email, and unsubscribed. So the webhook needs both "may be absent" and "may be null", while the REST types only need the latter.

Optional[str] is already the convention here for nullable response fields, matching ApiKey.last_used_at and the DomainClaim fields.

Request types (CreateParams, UpdateParams) are untouched, since those are inputs.

Verification

mypy is clean on both changed files. The only errors it reports are the pre-existing missing stubs for httpx and requests, which are unrelated.

No test added. These are TypedDicts with no runtime validation, so a test here could only assert that json.loads returns None for null, which restates the language rather than the contract. Happy to add one if you would rather have the documentation value.

Related

Spec fix in resend/resend-openapi#91, which makes the same correction to GetContactResponseSuccess, ListContactsResponseSuccess, and ContactEventData.

Ref DEV-1625


Summary by cubic

Aligns contact name types with actual API behavior to prevent type-checked code from assuming strings when null is returned (DEV-1625). Previously first_name/last_name were NotRequired[str]; now REST Contact uses Optional[str], and webhook ContactEventData uses NotRequired[Optional[str]].

  • Migration:
    • When reading Contact.first_name or Contact.last_name, handle None before calling string methods.
    • Webhook handlers must continue to handle missing keys and handle None when keys exist.
    • No changes to request params or runtime behavior.

Written for commit 08b6d5e. Summary will update on new commits.

Review in cubic

NotRequired[str] said the key may be absent but promised a real str when
present. The API returns null, which is the case that type ruled out.

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

@cubic-dev-ai cubic-dev-ai Bot 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.

cubic analysis

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Linked issue analysis

Linked issue: DEV-1625: Allow nullable contact first and last names in OpenAPI

Status Acceptance criteria Notes
Contact first_name and last_name allow null values in retrieve/list response types. The Contact TypedDict fields changed from NotRequired[str] to Optional[str].
Webhook contact first_name and last_name allow both missing keys and null values. The webhook fields retain NotRequired while adding Optional[str] for their values.

Auto-approved: Corrects TypedDict types to match actual API behavior (null names), supported by live fixtures and existing Optional convention. Pure type-contract fix with no runtime or operational impact.

Re-trigger cubic

Approval not submitted

This repository is configured to approve as @klotty, but that approval identity is unavailable.
Reconnect or verify the approval identity in repository settings.

cubic left this as a normal review comment instead of falling back to a Cubic App approval.

@gabrielmfern gabrielmfern self-assigned this Aug 17, 2026
@gabrielmfern
gabrielmfern marked this pull request as ready for review August 17, 2026 20:23
@gabrielmfern
gabrielmfern marked this pull request as draft August 17, 2026 20:27
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.

2 participants