Skip to content

feat(spec): add INCOMING_PAYMENT.PROCESSING to the webhook contract - #858

Merged
shreyav merged 1 commit into
mainfrom
claude/incoming-processing-webhook
Aug 24, 2026
Merged

feat(spec): add INCOMING_PAYMENT.PROCESSING to the webhook contract#858
shreyav merged 1 commit into
mainfrom
claude/incoming-processing-webhook

Conversation

@shreyav

Copy link
Copy Markdown
Contributor

Note

Bottom of a three-PR stack, based on main and mergeable on its own. #856 and #857 sit on top of it. Deliberately isolated so the sparkcore fix that depends on this enum isn't blocked behind the docs work above.

The bug

WebhookType describes itself as dot-notation that "lets consumers route purely on type without inspecting data.status".

The incoming family breaks that promise. _get_incoming_webhook_type (sparkcore/grid/webhooks/webhook_handler.py:142) collapses four states onto one event:

case (CREATED|PENDING|PROCESSING|SENT):
returnWebhookType.INCOMING_PAYMENT_DOT_PENDING

The outgoing twin 24 lines above maps PROCESSING to its own event. So a pull into an internal account fires INCOMING_PAYMENT.PENDINGtwice, and the second payload carries "status": "PROCESSING" inside an envelope typed PENDING — exactly the inspect-data.status case the contract says consumers should not need.

Likely why it went unnoticed: the receive-operation path (ordinary deposits) does not appear to reach PROCESSING/SENT, so the collapse was harmless. GK.GRID_INCOMING_TRANSACTION_REFACTOR then routed send operations — which do pass through those states — into this function without extending it.

This PR

Contract only. Adds INCOMING_PAYMENT.PROCESSING to WebhookType and to the IncomingPaymentWebhooktype enum, mirroring the outgoing family.

sparkcore does not emit the event yet. Its WebhookType is generated from this spec, so this has to land before the emission fix can reference the new member.

Follow-up in webdev, after this merges

  1. Regenerate the grid-api Python SDK so WebhookType.INCOMING_PAYMENT_DOT_PROCESSING exists.
  2. Split PROCESSING | SENT out of the PENDING case in _get_incoming_webhook_type. SENT belongs with PROCESSING, not PENDINGgen_convert_send_op_to_incoming_transaction already maps SENT onto status PROCESSING (transaction.py:891), so that is what makes the envelope agree with its payload.

Note for whoever picks that up: it changes behavior for existing integrators, who currently receive two PENDING events and will start receiving PENDING then PROCESSING.

A smaller instance of the same collapse is out of scope here: _get_incoming_webhook_type also folds EXPIRED into INCOMING_PAYMENT.FAILED.

Validation

CheckResult
make lintexit 0 — 0 errors
make build + bundle syncopenapi.yaml / mintlify/openapi.yaml in sync
oasdiff 1.16.0 vs mainno breaking changes — adding an enum value widens the contract

Generated by Claude Code

WebhookType describes itself as dot-notation that "lets consumers route
purely on type without inspecting data.status". The incoming family breaks
that promise: it has no PROCESSING event, so sparkcore's
_get_incoming_webhook_type collapses CREATED, PENDING, PROCESSING and SENT
onto INCOMING_PAYMENT.PENDING, while the outgoing equivalent gives
PROCESSING its own event.
A pull into an internal account therefore fires PENDING twice, and the
second payload carries status PROCESSING inside an envelope typed PENDING
— exactly the inspect-data.status case the contract says consumers should
not need.
Adds the value to WebhookType and to the IncomingPaymentWebhook type enum,
mirroring the outgoing family. Contract only: sparkcore does not emit the
event yet, and its WebhookType is generated from this spec, so this has to
land before the emission fix can reference the new member.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
@mintlify

mintlifyBot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

ProjectStatusPreviewUpdated (UTC)
Grid🟢 ReadyView PreviewAug 24, 2026, 4:12 AM

@vercel

vercelBot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
ProjectDeploymentActionsUpdated (UTC)
grid-flow-builderIgnoredIgnoredAug 24, 2026 4:11am
grid-wallet-demoIgnoredIgnoredAug 24, 2026 4:11am

Request Review

@github-actions

github-actionsBot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

cli

chore(internal): regenerate SDK with no functional changes

go

feat(api): add processing status to incoming payment webhook events

kotlin

feat(api): add INCOMING_PAYMENT_PROCESSING to IncomingPaymentWebhookEvent

openapi

feat(api): add PROCESSING event to incoming payments

php

feat(api): add PROCESSING status to IncomingPaymentWebhookEvent

python

feat(api): add INCOMING_PAYMENT.PROCESSING event type to incoming payment webhooks

ruby

feat(api): add processing status to incoming payment webhook events

typescript

feat(api): add INCOMING_PAYMENT.PROCESSING event type to webhooks
⚠️grid-openapistudio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️

⚠️grid-rubystudio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️build ✅lint ✅test ✅

⚠️grid-gostudio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ⚠️build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@4bea1b99560e2eae637d18c71828fc4e1248640d
⚠️grid-kotlinstudio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
generate ⚠️build ✅lint ✅test ❗

⚠️grid-typescriptstudio · conflict

Your SDK build had at least one warning diagnostic.

⚠️grid-pythonstudio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ⚠️build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/ac31e55c0046d3fdb2407427ff6abb0d9414f8f5/grid-0.0.1-py3-none-any.whl
⚠️grid-phpstudio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️lint ✅test ✅

⚠️grid-clistudio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
generate ⚠️build ⏭️lint ⏭️test ❗


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-08-24 15:51:00 UTC

@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds INCOMING_PAYMENT.PROCESSING to the shared webhook type registry and incoming-payment payload contract, preparing generated clients for a subsequent emitter change.

  • Updates both modular webhook schemas with the new event value.
  • Synchronizes the generated root and Mintlify OpenAPI bundles.
  • Keeps the shared event registry and incoming-payment schema narrowing aligned.

Confidence Score: 5/5

The PR appears safe to merge because the additive event value is consistently represented across the authoritative schemas and generated bundles.

The shared webhook registry and incoming-payment payload enum remain aligned, no additional discriminator or registry requires updating, and the generated contracts mirror the modular source.

Important Files Changed

FilenameOverview
openapi/components/schemas/webhooks/WebhookType.yamlAdds the processing event to the authoritative shared webhook type registry.
openapi/components/schemas/webhooks/IncomingPaymentWebhook.yamlAdds the same event to the incoming-payment webhook's narrowed type enum.
openapi.yamlCorrectly mirrors both source-schema additions in the generated bundled contract.
mintlify/openapi.yamlKeeps the Mintlify contract bundle synchronized with the generated root contract.

Reviews (1): Last reviewed commit: "feat(spec): add INCOMING_PAYMENT.PROCESS..." | Re-trigger Greptile

@shreyav
shreyav requested a review from pengyingAugust 24, 2026 14:45
@shreyav
shreyav merged commit 6d2e6bc into mainAug 24, 2026
10 checks passed
@shreyav
shreyav deleted the claude/incoming-processing-webhook branch August 24, 2026 15:42
shreyav added a commit that referenced this pull request Aug 24, 2026
…857)
> [!NOTE]
> **Top of a three-PR stack:** #858 (spec) → #856 (transfer deprecation)
→ this. Base is `claude/transfer-api-deprecation-docs-6ycamq`, so the
diff here is only the 3 files below. Each merge retargets this
automatically.
## The gap
Nothing in the docs said whether a given transfer produces an `INCOMING`
or an `OUTGOING` transaction. Worse, the Transaction Lifecycle page
contained **zero occurrences of the word "incoming"** — it described
only the outgoing flow, despite `INCOMING_PAYMENT.*` webhooks existing
and being referenced from six other pages.
## The rule
The type is keyed on the **destination**, regardless of source:
| Destination | `type` | Webhook family |
|---|---|---|
| Internal account | `INCOMING` | `INCOMING_PAYMENT.<STATUS>` |
| External account | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` |
| UMA address | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` |
Consequences worth spelling out, and now spelled out:
- A pull from an external account into an internal account is
`INCOMING`, even though the platform initiated it.
- A transfer between two internal accounts is `INCOMING`.
- A deposit that lands by paying an internal account's payment
instructions is `INCOMING`, as is a payment received at a customer's UMA
address.
This mirrors the dispatch in `gen_convert_to_transaction`
(`sparkcore/grid/objects/transaction.py:159`), which routes
`EntGridReceiveOperation` to incoming unconditionally and branches a
send operation on `gen_send_op_destination_is_internal_account`. That
helper carries the same truth table in its docstring at
`transaction.py:738`. The branch is gated on
`GK.GRID_INCOMING_TRANSACTION_REFACTOR`, which is rolled out, so the
table describes current behavior for all platforms.
## Changes
- **`transaction-lifecycle.mdx`** — new **Incoming or outgoing** section
at the top, ahead of the flow sections, since the type decides which
lifecycle and webhook family apply.
- **`transaction-lifecycle.mdx`** — split the webhook event table into
outgoing and incoming families. The incoming list was missing entirely.
Its `INCOMING_PAYMENT.PROCESSING` row corresponds to the enum value
added in #858.
- **`terminology.mdx`** — said the type was "from the platform's
perspective", which does not tell a reader how to predict it. Now states
the rule.
- **`list-transactions.mdx`** — the *Filter by transaction type* section
had the reader choosing `type=INCOMING|OUTGOING` with no way to know
which their payout is. Now states the rule and links to the table.
## Two things this PR previously got wrong
Recorded because both were corrected in place and a reviewer reading
only the head would not see them:
1. An early revision claimed incoming transactions have no `PROCESSING`
**state**. False — they do; both incoming converters map
`display_status` through, and
`gen_convert_send_op_to_incoming_transaction` maps `SENT` onto
`PROCESSING` explicitly (`transaction.py:891`). Only the *webhook event*
is missing.
2. The next revision then explained that missing event as an intentional
design difference, which would have enshrined a bug. It is a sparkcore
bug; #858 adds the enum and describes the emission fix.
## Validation
- `make lint` exits 0 — 663 problems, unchanged from baseline (all
pre-existing)
- Docs-only: no files under `openapi/`, so the bundle, oasdiff, and SDK
generation are untouched by this PR
- The `#incoming-or-outgoing` anchor is linked from
`list-transactions.mdx`; the heading carries no punctuation, so the slug
is unambiguous
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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

@shreyav@wuvictor-95