Skip to content

docs: add the /v2/secure-payments surface to openapi.v2.json - #111

Open
rodrigopavezi wants to merge 2 commits into
mainfrom
docs/openapi-secure-payments
Open

docs: add the /v2/secure-payments surface to openapi.v2.json#111
rodrigopavezi wants to merge 2 commits into
mainfrom
docs/openapi-secure-payments

Conversation

@rodrigopavezi

@rodrigopavezi rodrigopavezi commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Why

api-reference/openapi.v2.json was missing the entire /v2/secure-payments surface — including POST /v2/secure-payments, the primary flow the prose docs teach (secure-payments.mdx, secure-payment-integration-guide.mdx, programmatic-payment-links.mdx, llm-integration-guide.mdx) — and POST /v2/secure-payments/multicall-payouts.

docs.json auto-generates the Endpoints (V2) playground pages from this file, so none of these endpoints had a reference page, and rules like the optionality of requests[].destinationId could only be sourced from prose. Found while fixing a review comment on #106.

What

Adds 12 operations across 11 paths under the V2/Secure Payment tag (which was already listed in x-tagGroups but had no tag entry and no paths), reconciled against RequestNetwork/request-api @ 0.28.0 — verified identical on main and staging.

Path Ops
/v2/secure-payments POST, GET
/v2/secure-payments/payouts POST
/v2/secure-payments/batch-payouts POST
/v2/secure-payments/fees/preview POST
/v2/secure-payments/{token} GET
/v2/secure-payments/{token}/pay GET
/v2/secure-payments/{token}/intent POST
/v2/secure-payments/{token}/tron/broadcast POST
/v2/secure-payments/{token}/refresh-step-transaction POST
/v2/secure-payments/multicall-payouts POST
/v2/secure-payments/multicall-payouts/{token} GET

Purely additive — 6803 insertions, 0 deletions.

The live spec could not be copied verbatim

Schemas here are generated from the zod schemas in src/validation/schemas/secure-payment.schema.ts, not copied from https://api.request.network/open-api/openapi.json.

The @Route decorator's generateSchema() helper does:

const generatedComponent = generator.generateComponents();
const firstSchemaKey = Object.keys(generatedComponent.components.schemas)[0];
return generatedComponent.components.schemas[firstSchemaKey];

When a schema references another .openapi()-registered schema, the nested one is registered first, so [0] returns the wrong component. Concretely, the live spec advertises the fee plan snapshot as the 201 body of POST /v2/secure-payments, when the real body is { requestIds, securePaymentUrl, token, feePlan }. Same failure mode for GetSecurePaymentResponse, GetSecurePaymentCalldataResponse, SecurePaymentInfoResponse, MulticallPayoutDetailsResponse, RecordSecurePaymentIntent(Response), and the TRON broadcast body — several of which the served spec truncates to a fraction of the real shape.

The generated schemas are fully inlined (this file has no components.schemas) and emitted as OpenAPI 3.0nullable: true rather than type: [..., "null"], boolean exclusiveMinimum — matching the "openapi": "3.0.0" this file declares.

Corrections beyond the served spec

  • token path parameter added on GET /{token} and GET /{token}/pay. The served spec declares only the same-named query parameter (the crosschain source currency USDC / USDT / EURC / USDT0), leaving the path parameter undeclared entirely. Both are now present, each describing what it is and that they are different values.
  • Authorization header added to the operations whose guard accepts a session (POST /, /payouts, /batch-payouts, /fees/preview, /multicall-payouts). The decorator emits it only for auth: "session" endpoints, so session auth was silently undocumented on the combined guards. Described with the guard's real precedence: orchestrator key → api key / client id → session.
  • isSafe enum restored ("true" / "false") — dropped by the decorator because the zod enum sits behind a .transform().
  • requests[].destinationId documented from secure-payment.service.ts, not just as "optional":

    Optional. The server always resolves the destination itself — from the payee destination bound to the authenticating Client ID, falling back to the platform's active destination — so you can omit this field whenever the Client ID has a bound payee destination. When you do send it, it must equal the resolved destination ID: a different value is rejected with 403 Destination does not match the configured payment destination. Every item in requests[] therefore resolves to the same destination. A backend Client ID (one with no allowed domains) must be bound to a payee destination, otherwise creation fails with 403.

  • 401 added to every operation, plus the concrete 400 and 403 cases on POST /v2/secure-payments (mixed networks, TRON batch, no active destination, destination mismatch, non-wallet platform, unbound backend Client ID).
  • batchPayment example fixed (flagged by Greptile). Upstream it gives its two items different destinationId values, which 403s under the invariant above. Both items now share one destination, the constraint is restated on requests[] itself, and a singlePaymentResolvedDestination example shows the omitted form the field description recommends.

Verification

  • openapi-spec-validator against OpenAPI 3.0: everything added validates cleanly. The single remaining error is pre-existing and unrelated/v2/payee-destination/{destinationId} has no destinationId path parameter on its get/delete. It fails on main today and is untouched here.
  • No 3.1-only constructs, no duplicate (name, in) parameter pairs, and every {param} in the added path templates has a matching in: path parameter.
  • Auth, status codes, and field semantics cross-checked against secure-payment.controller.ts, secure-payment-multicall.controller.ts, secure-payment.service.ts, and the guards.

Follow-ups (not in this PR)

  1. request-api: generateSchema() in src/decorators/route.decorator.ts should resolve the schema by its registered refId instead of Object.keys(...)[0]. Until then the live /open-api spec and Scalar UI keep serving wrong response shapes for any schema that nests a registered one.
  2. request-api: neither GET /{token} nor /{token}/pay declares a token path parameter, and the combined-auth endpoints never document Authorization. Fixing the decorator would let this file be regenerated rather than hand-reconciled.
  3. request-api: the batchPayment body example on SecurePaymentController.createSecurePayment uses two different destinationId values, which the service rejects with 403. The stale example is the origin of the one corrected here, and it is still what the live Scalar UI shows.
  4. Prose drift in api-reference/secure-payments.mdx: the GET /v2/secure-payments/:token cURL example sends x-api-key, but that endpoint is auth: "clientId" (needs x-client-id + Origin); the crosschain source-token list omits EURC and USDT0; and the 201 response examples omit feePlan.
  5. api-reference/endpoints-overview.mdx has no Secure Payments section — it also already omits Currencies, Client IDs, and Payee Destination, so it wants one pass rather than a partial addition.

The spec was missing every secure-payments endpoint, including
POST /v2/secure-payments — the primary flow the prose docs teach — and
POST /v2/secure-payments/multicall-payouts. Because docs.json auto-generates
the "Endpoints (V2)" playground pages from this file, none of them had a
reference page, and rules like the optionality of requests[].destinationId
could only be sourced from prose.

Adds all 12 operations across 11 paths under the V2/Secure Payment tag,
reconciled against the request-api implementation (RequestNetwork/request-api
@ 0.28.0, identical on main and staging).

Schemas are generated from the zod schemas in
src/validation/schemas/secure-payment.schema.ts rather than copied from the
live /open-api/openapi.json, because the Route decorator's generateSchema()
helper takes Object.keys(components.schemas)[0] and so mis-picks a nested
component whenever a schema references another registered one. The served
spec is wrong for SecurePaymentResponse (shows the fee plan snapshot),
GetSecurePaymentResponse, GetSecurePaymentCalldataResponse,
SecurePaymentInfoResponse, MulticallPayoutDetailsResponse,
RecordSecurePaymentIntent(Response), and the TRON broadcast body.

Also corrected against the source:

- Added the missing `token` path parameter on GET /v2/secure-payments/{token}
  and /{token}/pay. The served spec only declares the same-named *query*
  parameter (the crosschain source currency), which left the path parameter
  undeclared and the two meanings conflated. Both are now documented.
- Added the `Authorization` header to the operations whose guard accepts a
  session, with the guard's actual precedence (orchestrator key, then
  api key / client id, then session).
- Added `enum: ["true", "false"]` to the `isSafe` query parameter, which the
  decorator drops because the zod enum sits behind a transform.
- Documented `requests[].destinationId` from the service: the server always
  resolves the destination itself, a mismatched value is rejected with 403,
  and a backend Client ID must be bound to a payee destination.
- Added 401 to every operation, plus the 400/403 cases on
  POST /v2/secure-payments.

Schemas are emitted as OpenAPI 3.0 (nullable, boolean exclusiveMinimum) to
match the "openapi": "3.0.0" this file declares. The additions validate
cleanly; the one pre-existing validation error on
/v2/payee-destination/{destinationId} is untouched and unrelated.
@mintlify

mintlify Bot commented Jul 28, 2026

Copy link
Copy Markdown

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

Project Status Preview Updated (UTC)
request-network 🟢 Ready View Preview Jul 28, 2026, 12:40 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread api-reference/openapi.v2.json Outdated
@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown

Greptile Summary

Adds the Secure Payments V2 API surface to the OpenAPI specification.

  • Documents 12 operations across 11 secure-payment paths.
  • Defines request and response schemas, authentication parameters, status codes, and examples.
  • Corrects the batch-payment example so every request uses the same resolved destination.

Confidence Score: 5/5

The PR appears safe to merge.

The previously reported batch-payment example is corrected at api-reference/openapi.v2.json:5648-5652, where both items now use the same destination ID, and no blocking failure remains.

Important Files Changed

Filename Overview
api-reference/openapi.v2.json Adds the Secure Payments endpoint contract; the previously reported batch example now uses the same destination ID for both requests and clearly documents the invariant.

Reviews (2): Last reviewed commit: "docs: fix the batch example to respect t..." | Re-trigger Greptile

The batchPayment example, copied verbatim from the @route decorator in
request-api, gave its two items different destinationId values. Since
createSecurePayment resolves one destination for the caller and rejects any
supplied destinationId that differs from it, copying that example produces a
403 "Destination does not match the configured payment destination." rather
than a batch payment.

Both items now use the same destinationId, and the summary says so. Also
states the constraint on the requests[] array itself, so it is visible to
callers who omit destinationId and never read that field's description, and
adds an example of the omitted form — the flow the destinationId docs
describe but had no example for.
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