Skip to content

feat: add TransactionFeeConfig schema (AT-5613)#613

Open
jacklatourette wants to merge 4 commits into
mainfrom
06-23-feat_grid-api_add_transactionfeeconfig_schema_at-5613_
Open

feat: add TransactionFeeConfig schema (AT-5613)#613
jacklatourette wants to merge 4 commits into
mainfrom
06-23-feat_grid-api_add_transactionfeeconfig_schema_at-5613_

Conversation

@jacklatourette

@jacklatourette jacklatourette commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Reason

Ships AT-5613 (Xc) of the Platform Fee Config: Cross Currency epic — Grid API OpenAPI schemas for platform-collected transaction fees.

This is the API-surface ticket that the sparkcore PATCH /config handler (AT-5614) and the Grid API SDKs will consume.

Overview

Two new schemas + extensions to two existing ones:

  • TransactionFeeConfig.yaml{ id, feeEventType, sourceCurrency, variableFeeBps, fixedFee, isActive }. id and isActive are read-only. Required: feeEventType, sourceCurrency, variableFeeBps, fixedFee.
  • TransactionFeeEventType.yaml — enum { CROSS_CURRENCY_TRANSACTION, TRANSFER_OUT_TRANSACTION }. Intentionally broad — sparkcore enforces a narrower v0 whitelist (CROSS_CURRENCY_TRANSACTION only) at the handler layer (AT-5614) so the Transfer Out fast-follow does not need an SDK regen.
  • PlatformConfig.yaml — adds optional transactionFeeConfigs: array. Reads return all active rows regardless of feeEventType, so operator-planted Transfer Out rows are visible to platforms before the write path is enabled.
  • PlatformConfigUpdateRequest.yaml — same field. Documented as merge-by-key upsert on (feeEventType, sourceCurrency); "deactivate" = same key with variableFeeBps: 0 and fixedFee.amount: 0.

Test Plan

  • Bundle: npm run build:openapi clean — both new schemas auto-discovered into openapi.yaml (lines 8857 + 8904) and the mintlify/openapi.yaml mirror.
  • Redocly lint: validates clean (Your API description is valid 🎉). The pre-existing 33 warnings are all on unrelated webhook example schemas (none on the files this PR touches). Confirmed by running npm run lint against main first — same 33.
  • Spectral: pre-existing spectral: command not found issue on main — the npm script tries npx spectral which resolves to a 0.0.0 placeholder package, not @stoplight/spectral-cli. Not introduced by this PR; tracking separately.
  • Stainless: regen kicks in on merge.

Manual SDK-shape check (post-Stainless regen)

After Stainless picks this up, the generated TS SDK should expose:

  • TransactionFeeConfig type with the shape above
  • TransactionFeeEventType union including both CROSS_CURRENCY_TRANSACTION and TRANSFER_OUT_TRANSACTION
  • PlatformConfig.transactionFeeConfigs?: TransactionFeeConfig[]
  • PlatformConfigUpdateRequest.transactionFeeConfigs?: TransactionFeeConfig[]

Blocked on

Nothing — this lands in parallel with AT-5611/AT-5612 sparkcore work.

Unblocks

  • AT-5614 — sparkcore PATCH /config handler that consumes transactionFeeConfigs and enforces v0 validation
  • All downstream API consumers

@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Jun 25, 2026 10:39pm
grid-wallet-demo Ignored Ignored Preview Jun 25, 2026 10:39pm

Request Review

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

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

cli

feat(api): add transaction-fee-config parameter to config update method

csharp

feat(api): add transactionFeeConfigs field and types to config models

go

feat(api): add transaction fee configs to platform config and CurrencyAmountParam type

kotlin

feat(api): add transactionFeeConfigs to PlatformConfig request/response

openapi

feat(api): add transaction fee config types and fields to PlatformConfig

php

feat(api): add transactionFeeConfigs field and TransactionFeeConfig type to config

python

feat(api): add transaction_fee_configs parameter to config update method

ruby

feat(api): add transaction_fee_configs field and nested model to platform config

typescript

feat(api): add transactionFeeConfigs parameter and field to config

Edit this comment to update them. They will appear in their respective SDK's changelogs.

grid-openapi studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅

grid-ruby studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-go studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@6d11a4c0e65a8d7bed314ac1b140b7b3ae6cd001
grid-typescript studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

npm install https://pkg.stainless.com/s/grid-typescript/1e1f47a49a4a6028e328e2a1c76d899c6b99238a/dist.tar.gz
grid-kotlin studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-python studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/e4623e7b2178aa41ad022665442e32063e4951eb/grid-0.0.1-py3-none-any.whl
⚠️ grid-csharp studio · code · diff

Your SDK build had at least one new warning diagnostic, which is a regression from the base state.
generate ⚠️build ❗lint ✅test ❗

New diagnostics (1 warning)
⚠️ Schema/CannotInferName: Placeholder name generated for schema.
grid-php studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅lint ✅test ✅

grid-cli studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
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-06-25 22:45:46 UTC

@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Introduces TransactionFeeConfig and TransactionFeeConfigInput OpenAPI schemas for platform-collected transaction fees, extends PlatformConfig (read) and PlatformConfigUpdateRequest (write) with an optional transactionFeeConfigs array, and registers all three new schemas in Stainless for SDK codegen.

  • TransactionFeeConfig is the read-side schema (used in GET responses); TransactionFeeConfigInput is the write-side variant that correctly omits id/isActive and adds a minimum: 0 constraint on fixedFee.amount via allOf.
  • TransactionFeeEventType enum ships both CROSS_CURRENCY_TRANSACTION and TRANSFER_OUT_TRANSACTION upfront; current server enforcement is narrower and documented inline, so the schema can expand without an SDK regen.
  • Currency and CurrencyAmount are moved earlier in the bundled files to appear upstream of the schemas that reference them — no functional change.

Confidence Score: 5/5

Safe to merge — schema-only change with no runtime logic, Redocly lint passes clean, and the read/write schema split is correctly implemented.

All new schemas are well-formed OAS 3.1, the read/write separation via TransactionFeeConfig vs TransactionFeeConfigInput is correctly wired, and the bundled outputs match the source files. The only nit is a deactivation write instruction left in the read schema's description.

TransactionFeeConfig.yaml — its top-level description still contains a write instruction that belongs only in TransactionFeeConfigInput.

Important Files Changed

Filename Overview
openapi/components/schemas/config/TransactionFeeConfig.yaml New read-side schema for platform transaction fees. Well-formed for OAS 3.1; top-level description includes a write instruction ("To deactivate…") that belongs only in TransactionFeeConfigInput.
openapi/components/schemas/config/TransactionFeeConfigInput.yaml New write-side schema for PATCH /config. Correctly omits readOnly fields, uses allOf to add minimum: 0 on fixedFee.amount, and carries the deactivation instruction appropriately.
openapi/components/schemas/config/TransactionFeeEventType.yaml New enum schema with CROSS_CURRENCY_TRANSACTION and TRANSFER_OUT_TRANSACTION values; includes clear description of current write-path restriction.
openapi/components/schemas/config/PlatformConfig.yaml Adds optional transactionFeeConfigs array using TransactionFeeConfig (read schema). Description correctly notes all feeEventType rows are visible on reads.
openapi/components/schemas/config/PlatformConfigUpdateRequest.yaml Adds optional transactionFeeConfigs array using TransactionFeeConfigInput (write schema). Documents merge-by-key upsert semantics and current USD-only restriction clearly.
.stainless/stainless.yml Registers all three new schemas (TransactionFeeConfig, TransactionFeeConfigInput, TransactionFeeEventType) for SDK codegen — looks correct.
openapi.yaml Bundled output: new schemas inserted correctly; Currency and CurrencyAmount moved earlier in the file (upstream of the new schemas that reference them). No structural issues.
mintlify/openapi.yaml Mirror of openapi.yaml for Mintlify docs. Identical changes, no issues.

Entity Relationship Diagram

%%{init: {'theme': 'neutral'}}%%
erDiagram
    PlatformConfig {
        string id
        object embeddedWalletConfig
        TransactionFeeConfig[] transactionFeeConfigs
        datetime createdAt
    }
    PlatformConfigUpdateRequest {
        object embeddedWalletConfig
        TransactionFeeConfigInput[] transactionFeeConfigs
    }
    TransactionFeeConfig {
        string id PK
        TransactionFeeEventType feeEventType
        string sourceCurrency
        int variableFeeBps
        CurrencyAmount fixedFee
        boolean isActive
    }
    TransactionFeeConfigInput {
        TransactionFeeEventType feeEventType
        string sourceCurrency
        int variableFeeBps
        CurrencyAmount fixedFee
    }
    TransactionFeeEventType {
        string CROSS_CURRENCY_TRANSACTION
        string TRANSFER_OUT_TRANSACTION
    }
    CurrencyAmount {
        int amount
        Currency currency
    }
    Currency {
        string code
        string name
        string symbol
        int decimals
    }
    PlatformConfig ||--o{ TransactionFeeConfig : "transactionFeeConfigs (read)"
    PlatformConfigUpdateRequest ||--o{ TransactionFeeConfigInput : "transactionFeeConfigs (write)"
    TransactionFeeConfig }|--|| TransactionFeeEventType : feeEventType
    TransactionFeeConfigInput }|--|| TransactionFeeEventType : feeEventType
    TransactionFeeConfig }|--|| CurrencyAmount : fixedFee
    TransactionFeeConfigInput }|--|| CurrencyAmount : fixedFee
    CurrencyAmount }|--|| Currency : currency
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
erDiagram
    PlatformConfig {
        string id
        object embeddedWalletConfig
        TransactionFeeConfig[] transactionFeeConfigs
        datetime createdAt
    }
    PlatformConfigUpdateRequest {
        object embeddedWalletConfig
        TransactionFeeConfigInput[] transactionFeeConfigs
    }
    TransactionFeeConfig {
        string id PK
        TransactionFeeEventType feeEventType
        string sourceCurrency
        int variableFeeBps
        CurrencyAmount fixedFee
        boolean isActive
    }
    TransactionFeeConfigInput {
        TransactionFeeEventType feeEventType
        string sourceCurrency
        int variableFeeBps
        CurrencyAmount fixedFee
    }
    TransactionFeeEventType {
        string CROSS_CURRENCY_TRANSACTION
        string TRANSFER_OUT_TRANSACTION
    }
    CurrencyAmount {
        int amount
        Currency currency
    }
    Currency {
        string code
        string name
        string symbol
        int decimals
    }
    PlatformConfig ||--o{ TransactionFeeConfig : "transactionFeeConfigs (read)"
    PlatformConfigUpdateRequest ||--o{ TransactionFeeConfigInput : "transactionFeeConfigs (write)"
    TransactionFeeConfig }|--|| TransactionFeeEventType : feeEventType
    TransactionFeeConfigInput }|--|| TransactionFeeEventType : feeEventType
    TransactionFeeConfig }|--|| CurrencyAmount : fixedFee
    TransactionFeeConfigInput }|--|| CurrencyAmount : fixedFee
    CurrencyAmount }|--|| Currency : currency
Loading

Reviews (6): Last reviewed commit: "fix(config): enforce fixedFee.amount >= ..." | Re-trigger Greptile

Comment thread openapi/components/schemas/config/TransactionFeeConfig.yaml
Comment on lines +1 to +10
type: object
description: >-
Platform-collected transaction fee charged on top of corridor fees. Keyed
uniquely by `(feeEventType, sourceCurrency)` within a platform. To deactivate
a fee, send the same key with `variableFeeBps: 0` and `fixedFee.amount: 0`.
required:
- feeEventType
- sourceCurrency
- variableFeeBps
- fixedFee

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Single schema reused for read and write contexts

TransactionFeeConfig is referenced by both PlatformConfig (GET response) and PlatformConfigUpdateRequest (PATCH body). In the write context, readOnly fields (id, isActive) appear in generated SDK request types — even though spec-compliant generators should strip them, some won't. Consider a dedicated TransactionFeeConfigInput schema for the write path that omits id and isActive entirely, so write-side types are unambiguous without relying on readOnly semantics being respected by all toolchains.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/config/TransactionFeeConfig.yaml
Line: 1-10

Comment:
**Single schema reused for read and write contexts**

`TransactionFeeConfig` is referenced by both `PlatformConfig` (GET response) and `PlatformConfigUpdateRequest` (PATCH body). In the write context, `readOnly` fields (`id`, `isActive`) appear in generated SDK request types — even though spec-compliant generators should strip them, some won't. Consider a dedicated `TransactionFeeConfigInput` schema for the write path that omits `id` and `isActive` entirely, so write-side types are unambiguous without relying on `readOnly` semantics being respected by all toolchains.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@jacklatourette jacklatourette force-pushed the 06-23-feat_grid-api_add_transactionfeeconfig_schema_at-5613_ branch from 6f07fa7 to c2ddd74 Compare June 23, 2026 20:42
jacklatourette and others added 3 commits June 25, 2026 14:19
Adds platform-collected transaction-fee configuration to the Grid API
PlatformConfig surface.

- New TransactionFeeConfig schema: { id, feeEventType, sourceCurrency,
  variableFeeBps, fixedFee, isActive }. `id` and `isActive` are
  read-only.
- New TransactionFeeEventType enum: { CROSS_CURRENCY_TRANSACTION,
  TRANSFER_OUT_TRANSACTION }.
- PlatformConfig: optional `transactionFeeConfigs: array`. Reads return
  all active rows regardless of feeEventType so operator-created Transfer
  Out rows are visible before the corresponding write path is enabled.
- PlatformConfigUpdateRequest: same field, with semantics documented as
  merge-by-key upsert on (feeEventType, sourceCurrency). To deactivate a
  fee, send the same key with variableFeeBps=0 and fixedFee.amount=0.
  Sparkcore's PATCH /config handler (AT-5614) will accept only
  feeEventType=CROSS_CURRENCY_TRANSACTION + sourceCurrency=USD for v0;
  the OpenAPI enum is intentionally broader so the Transfer Out
  fast-follow does not need an SDK regen.
The platform transaction fee's fixedFee.amount is enforced non-negative
server-side in sparkcore (PATCH /config); document it on the schema so
integrators see the constraint. CurrencyAmount stays unconstrained since
negative amounts are valid elsewhere in the API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…5613)

Add TransactionFeeConfigInput for the PATCH /config write path, omitting the
read-only id/isActive fields, so generated SDK request types are unambiguous and
do not rely on every toolchain stripping readOnly. This fixes the Stainless SDK
build regressions (csharp build, ruby/python lint, kotlin test) caused by the
read-only fields appearing in request types.

Also clarify the isActive read semantics (no filter param exists).
Addresses Greptile review feedback.
@jacklatourette jacklatourette force-pushed the 06-23-feat_grid-api_add_transactionfeeconfig_schema_at-5613_ branch from 6de5f40 to 9248a32 Compare June 25, 2026 21:19
…ive required (AT-5613)

Addresses Greptile review on the rebased PR:
- TransactionFeeConfigInput.fixedFee now constrains amount to minimum: 0 (via
  allOf over CurrencyAmount), so negative fixed fees are rejected at schema
  validation instead of an undocumented server 400.
- TransactionFeeConfig marks the always-present readOnly id and isActive as
  required, so generated SDK response types are non-optional.
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.

1 participant