Skip to content

feat: add raw_json() to the event returned by webhook verification - #652

Closed
razor-x wants to merge 1 commit into
mainfrom
claude/python-event-raw-json-mu1ldf
Closed

feat: add raw_json() to the event returned by webhook verification#652
razor-x wants to merge 1 commit into
mainfrom
claude/python-event-raw-json-mu1ldf

Conversation

@razor-x

@razor-x razor-x commented Sep 2, 2026

Copy link
Copy Markdown
Member

Follow-up to #651. That PR made parsing degrade instead of raise, but it did not keep the payload — so this is the half that actually lets a handler reach something the SDK does not know about yet.

The gap

from_dict reads only the properties it was generated for, so a field Seam adds to an existing event between SDK releases is silently discarded:

Device.from_dict({'device_id': 'd', 'brand_new_field': 'kept?'})
# brand_new_field: <<DROPPED>>

There was no way to recover it short of upgrading the SDK.

The change

SeamWebhook.verify() now returns an event carrying raw_json():

event = webhook.verify(payload, headers)
json.loads(event.raw_json())["a_field_this_version_predates"]

DeepAttrDict answers the same call, so the unrecognized-event branch and the typed branch are handled the same way. That matters more than it first appears: the fallback is not otherwise interchangeable with a generated event, because reading a missing key raises AttributeError where a dataclass returns None. Generic code written against the declared union breaks on it:

def log_any_event(ev):
    return f'{ev.event_type} in {ev.workspace_id}'

log_any_event(known_event)        # 'device.connected in w'
log_any_event(unrecognized_event) # AttributeError: workspace_id

raw_json() gives both branches one thing that always works.

Scope

Events only. It exists for the verify return, not as a general accessor on every model — Device, action attempts and the rest are untouched, and there is a test pinning that.

A method rather than a property because the call is where the serialization happens: the event retains the decoded payload and serializes on demand. The retained payload is repr=False and compare=False, so it changes neither the repr nor equality.

Verification

just lint && just test — 289 tests, mypy clean, pylint 10.00/10, black clean.

New tests cover recovering a dropped field, round-tripping a known and an unrecognized event, absence from the repr, equality being unaffected, and raw_json not leaking onto non-event models.

🤖 Generated with Claude Code

https://claude.ai/code/session_01M2kJ4nGaM8imZCVMEKjmXA


Generated by Claude Code

from_dict reads only the properties it was generated for, so a field Seam adds
to an existing event between SDK releases is silently discarded. #651 made
parsing degrade instead of raise, but did not keep the payload, so there was no
way to reach a new field short of upgrading.

SeamWebhook.verify() now returns an event carrying raw_json():

    json.loads(event.raw_json())["a_field_this_version_predates"]

DeepAttrDict answers the same call, so the unrecognized-event branch and the
typed branch are handled the same way. This matters because the fallback is not
otherwise interchangeable with a generated event: reading a missing key raises
AttributeError where a dataclass returns None, so generic code written against
the declared union breaks on it.

Scoped to events. It is there for the verify return, not as a general accessor
on every model. A method rather than a property because the call is where the
serialization happens; the event retains the decoded payload and serializes on
demand. The retained payload is repr=False and compare=False, so it changes
neither the repr nor equality.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M2kJ4nGaM8imZCVMEKjmXA
@razor-x
razor-x requested a review from a team as a code owner September 2, 2026 05:22
@razor-x razor-x closed this Sep 2, 2026
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