docs: document which transaction type a transfer or deposit creates - #857
docs: document which transaction type a transfer or deposit creates#857shreyav wants to merge 4 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
✱ Stainless preview builds for gridNo changes were made to the SDKs. This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
d7ea6db to
f313172
Compare
Greptile SummaryThis PR explains how transaction types determine lifecycle and webhook handling, then carries that guidance into transaction filtering and shared terminology.
Confidence Score: 4/5The documentation should be corrected before merging because its UMA-address row can direct integrations to use the wrong transaction type and webhook family. The new table says every UMA-address destination is outgoing, while both the same page and the incoming-payment contract show that payments received at customer UMA addresses are incoming. Files Needing Attention: mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx
|
| Filename | Overview |
|---|---|
| mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx | Adds transaction-type and incoming-webhook guidance, but the unconditional UMA-address row contradicts the documented and specified inbound UMA case. |
| mintlify/payouts-and-b2b/payment-flow/list-transactions.mdx | Adds filtering guidance and a valid root-relative link, while inheriting the lifecycle page's overly broad UMA classification. |
| mintlify/snippets/terminology.mdx | Replaces perspective-based terminology with destination-based wording, though the linked detailed explanation needs to distinguish inbound customer UMA addresses. |
Prompt To Fix All With AI
### Issue 1
mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx:19
**UMA destination rule misclassifies inbound payments**
When an integration classifies a payment received at a customer's UMA address, this unconditional `UMA address` → `OUTGOING` row conflicts with the documented and specified `INCOMING` transaction, causing the integration to filter for the wrong type or listen to the wrong webhook family.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "docs: list INCOMING_PAYMENT.PROCESSING i..." | Re-trigger Greptile
| |---|---|---| | ||
| | Internal account | `INCOMING` | `INCOMING_PAYMENT.<STATUS>` | | ||
| | External account | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` | | ||
| | UMA address | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` | |
There was a problem hiding this comment.
UMA destination rule misclassifies inbound payments
When an integration classifies a payment received at a customer's UMA address, this unconditional UMA address → OUTGOING row conflicts with the documented and specified INCOMING transaction, causing the integration to filter for the wrong type or listen to the wrong webhook family.
Knowledge Base Used: Payments, quotes, and transfers API
Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx
Line: 19
Comment:
**UMA destination rule misclassifies inbound payments**
When an integration classifies a payment received at a customer's UMA address, this unconditional `UMA address` → `OUTGOING` row conflicts with the documented and specified `INCOMING` transaction, causing the integration to filter for the wrong type or listen to the wrong webhook family.
**Knowledge Base Used:** [Payments, quotes, and transfers API](https://app.greptile.com/lightspark/-/custom-context/knowledge-base/lightsparkdev/grid-api/-/docs/payments-and-quotes-api.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.f313172 to
d3e5c01
Compare
…858) > [!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: ```python case (CREATED | PENDING | PROCESSING | SENT): return WebhookType.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.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. 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 `IncomingPaymentWebhook` `type` 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 `PENDING` — `gen_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 | Check | Result | |---|---| | `make lint` | exit 0 — 0 errors | | `make build` + bundle sync | `openapi.yaml` / `mintlify/openapi.yaml` in sync | | oasdiff 1.16.0 vs `main` | no breaking changes — adding an enum value widens the contract | --- _Generated by [Claude Code](https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv)_ Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Nothing in the docs said whether a given transfer produces an INCOMING or an OUTGOING transaction, and the transaction lifecycle page contained no occurrence of the word "incoming" at all — it described only the outgoing flow, despite INCOMING_PAYMENT webhooks existing and being referenced from six other pages. Added an "Incoming or outgoing" section at the top of that page with the rule and its table. The type is keyed on the destination, regardless of source: anything landing in an internal account is INCOMING, anything landing in an external account or at a UMA address is OUTGOING. So a pull from an external account is INCOMING even though the platform initiated it, a transfer between two internal accounts is INCOMING, and a deposit paid to an account's payment instructions is INCOMING. This mirrors the dispatch in sparkcore's gen_convert_to_transaction and the truth table on gen_send_op_destination_is_internal_account. Also split the webhook event table into outgoing and incoming families. The incoming list was missing entirely; it has no PENDING_AUTHORIZATION, PROCESSING, or EXPIRED event, which is worth stating since those belong to executing a quote. Terminology said the type was "from the platform's perspective", which does not tell a reader how to predict it, and the list-transactions type filter gave no way to know which value to pass. Both now state the rule and link to the table. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
…statuses The note claimed incoming payments have no PROCESSING. That is only true of the webhook event; the status exists. Both incoming converters map display_status straight through, and PROCESSING is a member of that enum. gen_convert_send_op_to_incoming_transaction goes further and maps SENT onto PROCESSING explicitly, so a pull into an internal account reports status PROCESSING while it is in flight even though no INCOMING_PAYMENT.PROCESSING webhook ever fires. Reworded to scope the claim to which events fire, and added a warning not to infer transaction state from webhook coverage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
…esign The previous note explained the absence of an INCOMING_PAYMENT.PROCESSING event as an intentional difference between the incoming and outgoing webhook families. It is not intentional — it is a sparkcore bug, so documenting a rationale for it would have enshrined it. _get_incoming_webhook_type collapses CREATED, PENDING, PROCESSING and SENT onto INCOMING_PAYMENT.PENDING, while the outgoing equivalent maps PROCESSING onto its own event. A pull into an internal account therefore signals PENDING twice, and the second payload carries status PROCESSING inside an envelope typed PENDING. The table still lists what fires today. Dropped the rationale and replaced it with a pointer to read status off the transaction, which stays true either way. The PROCESSING row lands here once sparkcore emits it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
The enum value lands in the spec one PR below this one. Adds its row to the incoming event table this PR introduces. Also drops the line telling readers the event name is a coarser signal than the status it carries. That was describing a bug as guidance: WebhookType is meant to be routable on its own, and once sparkcore emits PROCESSING it will be. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
d3e5c01 to
464ddc0
Compare
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
INCOMINGor anOUTGOINGtransaction. Worse, the Transaction Lifecycle page contained zero occurrences of the word "incoming" — it described only the outgoing flow, despiteINCOMING_PAYMENT.*webhooks existing and being referenced from six other pages.The rule
The type is keyed on the destination, regardless of source:
typeINCOMINGINCOMING_PAYMENT.<STATUS>OUTGOINGOUTGOING_PAYMENT.<STATUS>OUTGOINGOUTGOING_PAYMENT.<STATUS>Consequences worth spelling out, and now spelled out:
INCOMING, even though the platform initiated it.INCOMING.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 routesEntGridReceiveOperationto incoming unconditionally and branches a send operation ongen_send_op_destination_is_internal_account. That helper carries the same truth table in its docstring attransaction.py:738. The branch is gated onGK.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. ItsINCOMING_PAYMENT.PROCESSINGrow corresponds to the enum value added in feat(spec): add INCOMING_PAYMENT.PROCESSING to the webhook contract #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 choosingtype=INCOMING|OUTGOINGwith 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:
PROCESSINGstate. False — they do; both incoming converters mapdisplay_statusthrough, andgen_convert_send_op_to_incoming_transactionmapsSENTontoPROCESSINGexplicitly (transaction.py:891). Only the webhook event is missing.Validation
make lintexits 0 — 663 problems, unchanged from baseline (all pre-existing)openapi/, so the bundle, oasdiff, and SDK generation are untouched by this PR#incoming-or-outgoinganchor is linked fromlist-transactions.mdx; the heading carries no punctuation, so the slug is unambiguous