Add customer.* webhook events and customer_id list filters (wave 1) - #61
Conversation
…e 1) The deployed API has dual-emitted customer.new/update/delete alongside the legacy receiver.* webhook events since June, and already accepts customer_id as a query filter on GET payins/payouts and customer_id + customer_name on GET customers. The SDK never picked these up because api-sync only diffs receiver_* field renames, not new enum values. - WebhookEvents: add customer.new/update/delete, mark receiver.new/ update/delete @deprecated in place (still fires, not removed). - ListPayinsInput / ListPayoutsInput: add optional customer_id filter alongside the existing receiver_id. - customers resource list(): drop the customer_id/customer_name -> receiver_id/receiver_name translation shim now that the API accepts the customer_* names natively. - CLAUDE.md: fix stale UpdateReceiverInput/DeleteReceiverInput naming example and /receivers path examples that no longer match the code. Bump to 4.1.0 (minor, additive only). The remaining receiver_* -> customer_* field/error-code renames are deliberately not included here; the deployed API does not accept them until blindpay-v2 PR #1799 ships. Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
…ds with production The deployed API sends receiver_id in these response bodies, not customer_id. The customer_id name was applied optimistically ahead of the server-side rename (blindpay-v2 PR #1799, not yet deployed), so these fields never actually arrived on the wire. In Python/Swift this is a hard failure at deserialization; in TypeScript it silently resolved to undefined. Fixed schemas, confirmed 1:1 against the deployed openapi.json: - BlockchainWalletOut (list/get/create blockchain wallet responses) - OfframpWallet (list/get offramp wallet responses) - GetReceiverLimitIncreaseOut (get limit increase requests response) - ReceiverOut.owners[] (nested owner on customers.get()/list() for business customers) Left untouched: request-side customer_id path/body params (correct, matches the new /customers/... routes), receiver_amount, currency_type, and the bank-accounts owner-id field (pre-existing separate type-accuracy issue, out of scope here since the deployed BankAccountOut schema has neither receiver_id nor customer_id). Updated test fixtures accordingly and added type annotations to the offramp fixtures so a regression of this field name would now fail type-check. Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs
|
Added a second commit on top of the wave 1 work: fixed four response field declarations that had been renamed to Confirmed each one directly against the deployed
These are wave-1 safe: they align the SDK with what production sends today, they don't depend on PR #1799 shipping. Request-side Updated the test fixtures for all four, and added explicit type annotations to the offramp wallet fixtures so a regression of this exact bug would fail
|
…ase responses (#62) The wave 1 PR (#61) also merged a second commit that reverted BlockchainWalletOut, OfframpWallet and GetLimitIncreaseRequestsResponse to receiver_id, reasoning from the declared zod schema in openapi.json alone. That schema is not what leaves the socket: addCustomerIdMiddleware (apps/api/src/shared/helpers/customer-migration.ts) rewrites every customer-route response, adding customer_id wherever receiver_id is present, at both the top level and inside a response's data array. It does not recurse into nested object/array properties such as owners[]. So customer_id is already on the wire today for these three response shapes, and it is also the field name the post-#1799 spec declares once the server-side rename ships. Restore customer_id as required for the three affected shapes. The nested Owner.owners[] element is the one place the middleware does not reach today: declare both receiver_id and customer_id there as optional, since receiver_id is what production actually sends there now and customer_id is what it will send after #1799. Bump to 4.1.1 (patch: corrects a type declaration, no feature). Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs
What
This is wave 1 of the receivers -> customers migration for blindpay-node: only changes the currently deployed API already accepts. Nothing here requires blindpay-v2 PR #1799 (still open, not deployed) to be merged first.
WebhookEvents: addcustomer.new,customer.update,customer.deleteas new union members. Markreceiver.new,receiver.update,receiver.delete@deprecatedin place with a trailing comment (a plain string-literal union can't carry per-member JSDoc). Thereceiver.*members are NOT removed, they still fire in production today.ListPayinsInput/ListPayoutsInput: add an optionalcustomer_idfilter alongside the existingreceiver_id.customer_nameis intentionally NOT added to these two, the deployed API does not accept it there.customersresourcelist(): delete thecustomer_id/customer_name->receiver_id/receiver_namequery-param translation shim. The deployedGET /v1/instances/{instance_id}/customersendpoint already acceptscustomer_idandcustomer_namenatively, so the translation is now a no-op that was only adding indirection.CLAUDE.md: fix three stale doc examples (UpdateReceiverInput/DeleteReceiverInputnaming table, an offramp-wallet example still showing/receivers/{receiver_id}paths, a create-customer example still POSTing to/receivers) that no longer match what the code actually does.Also fixes: pre-existing wrong response field names
Independent of the receivers -> customers migration, a previous change had optimistically renamed some response field declarations to
customer_idahead of the server. The deployed API still sendsreceiver_idin these places today, so the SDK was declaring a key that never arrives on the wire (Python/Swift hard-fail on this; TypeScript silently resolves toundefined). Confirmed each one directly against the deployedopenapi.jsonbefore fixing:ListBlockchainWalletsResponse/GetBlockchainWalletResponse/CreateBlockchainWalletResponse: schemaBlockchainWalletOuthasreceiver_idinrequired, nocustomer_id.OfframpWallet(used by list/get offramp wallet responses): schemaOfframpWallethasreceiver_idinrequired, nocustomer_id.GetLimitIncreaseRequestsResponse: schemaGetReceiverLimitIncreaseOuthasreceiver_id, nocustomer_id.Ownertype oncustomers.get()/customers.list()for business customers: schemaReceiverOut.owners[]nestsreceiver_id, nocustomer_id.These are safe to land in wave 1 (unlike the wave 2 renames below) because they align the SDK with what production sends today, not with the not-yet-deployed rename. Request-side
customer_idpath/body params are untouched, they're correct since routes are already/customers/....receiver_amount,currency_type, and the bank-accounts owner-id field are untouched too, the latter is a separate pre-existing type-accuracy issue (deployedBankAccountOuthas neitherreceiver_idnorcustomer_id) left out of scope here.Test fixtures updated to match, and the offramp wallet fixtures now carry explicit type annotations so a regression of this exact bug fails
check-types.Why this is safe today
I diffed the deployed API's
openapi.jsonagainst this PR's changes before making them:customer.new/customer.update/customer.deleteare already in the deployedWebhookEndpointIn.eventsenum and the API has been dual-emitting bothreceiver.*andcustomer.*events since June.GET /v1/instances/{instance_id}/payinsand.../payoutsalready listcustomer_idas an accepted query parameter (verified per-endpoint;customer_nameis only accepted on.../customers, not on payins/payouts).GET /v1/instances/{instance_id}/customersalready lists bothcustomer_idandcustomer_nameas accepted query parameters, alongside the legacyreceiver_id/receiver_name.Purely additive, purely deprecation-marking, plus the response-field corrections above. No existing consumer's code path changes shape.
What is deliberately NOT in this PR (wave 2)
The remaining 11
receiver_*->customer_*body/response field renames (customer_local_amount,customer_wallet_address,customer_network,customer_token,customer_invite_redirect_url,receiver_idon payin/payout/transfer responses, etc.), theRECEIVERS_*->CUSTOMERS_*error-code/message renames, and removal ofreceiver.*from the webhook enum, are all held back on purpose. The deployed API does not accept the renamed field names yet, they only land once blindpay-v2 PR #1799 ships. Shipping those today would break every current SDK user sendingreceiver_*fields.Build output
Version
Bumped
package.jsonto4.1.0(minor, additive) and added a changeset (.changeset/customer-webhooks-and-list-filters.md), matching this repo's existing convention (e.g. #54 bumpedpackage.jsondirectly alongside its changeset in the same PR). Not bumped again for the field-name fixes added on top, they're covered by the same wave-1 minor bump.https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs