Skip to content

Comments

feat: Platform fee rules — configurable per-transaction-type markup#204

Open
jaymantri wants to merge 2 commits intomainfrom
feat/platform-fee-rules
Open

feat: Platform fee rules — configurable per-transaction-type markup#204
jaymantri wants to merge 2 commits intomainfrom
feat/platform-fee-rules

Conversation

@jaymantri
Copy link

Summary

Adds a complete CRUD API for platform-configurable fee rules, enabling Grid platforms to define per-transaction-type markup that layers on top of Lightspark and counterparty fees.

This closes the last major gap in the Grid pricing model: the API already surfaces fee fields on quotes and transactions (gridApiFixedFee, gridApiVariableFeeRate, gridApiVariableFeeAmount), but platforms had no way to configure their own markup. This PR adds that capability.

Fee architecture (three layers)

Layer Source Configurable by platform?
Network/rail fees Counterparty institution No
Lightspark fees Grid infrastructure No
Platform markup This PR Yes

New endpoints

Method Path Description
POST /fee-rules Create a fee rule (one per transaction type)
GET /fee-rules List all fee rules with optional filters
GET /fee-rules/{feeRuleId} Retrieve a single rule
PATCH /fee-rules/{feeRuleId} Partial update (amounts, enabled/disabled)
DELETE /fee-rules/{feeRuleId} Remove a rule
GET /fee-rules/report Monthly aggregated fee revenue by txn type

New schemas

  • FeeRule — the core entity with transactionType, feeType (FIXED / PERCENTAGE / HYBRID), fixedFee, variableFeeRate, enabled
  • FeeTransactionType — enum: TRANSFER_IN, TRANSFER_OUT, RAMP_ON, RAMP_OFF, CROSS_BORDER_PAYOUT
  • FeeRuleType — enum: FIXED, PERCENTAGE, HYBRID
  • FeeRuleCreateRequest / FeeRulePatchRequest — input schemas with validation constraints
  • FeeReport / FeeReportLine — monthly revenue aggregation

Extended existing schemas

OutgoingRateDetails and IncomingRateDetails gain three new optional fields so quotes and transactions surface platform markup alongside Lightspark fees:

  • platformFixedFee (int64, cents)
  • platformVariableFeeRate (double, e.g. 0.005 = 0.5%)
  • platformVariableFeeAmount (int64, cents, calculated)

New error codes

  • INVALID_FEE_RULE (400) — missing fields, amounts out of range, or wrong feeType/field combination
  • INVALID_MONTH_FORMAT (400) — month parameter not in YYYY-MM format
  • FEE_RULE_NOT_FOUND (404)
  • FEE_RULE_EXISTS (409) — duplicate transaction type

Documentation

  • Shared Mintlify snippet (snippets/platform-fee-rules.mdx) with layering explanation, cURL examples, and constraints
  • Wrapper pages in all four use-case tabs (Payouts & B2B, Ramps, Rewards, Global P2P) under Platform Tools
  • API reference auto-generated from OpenAPI spec

Design decisions

  1. One rule per transaction type — keeps the model simple and deterministic; no priority/ordering complexity
  2. variableFeeRate as a double — matches existing gridApiVariableFeeRate convention (not basis points)
  3. fixedFee in cents (int64) — matches existing gridApiFixedFee convention
  4. No pagination on list — max 5 rules (bounded by transaction type enum), pagination is unnecessary overhead
  5. feeType immutable on PATCH — avoids ambiguity about which fields become required/optional mid-lifecycle; delete and recreate instead
  6. Report endpoint under /fee-rules/report — colocated with rules since it's platform fee revenue, not general transaction analytics
  7. USD-only for now — fee collection currency matches the PRD; schema includes currency field for future multi-currency support

Test plan

  • npm run lint passes (Redocly validation confirmed clean)
  • npm run build:openapi bundles successfully
  • Verify new endpoints appear in Mintlify API Reference tab
  • Verify "Platform fee rules" guide renders correctly under Platform Tools in all four use-case tabs
  • Review schema examples render properly in Mintlify
  • Confirm rateDetails extensions don't break existing quote/transaction examples

Made with Cursor

@github-actions
Copy link

github-actions bot commented Feb 18, 2026

✱ Stainless preview builds

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

kotlin

feat(api): add fee rules endpoints, update OutgoingRateDetails/IncomingTransaction types

openapi

feat(api): add fee_rules endpoints, types, platform fee fields to quote details

python

feat(api): add fee_rules endpoints, platform fee fields to transaction types

typescript

feat(api): add fee_rules resource, platform fee fields to quotes/transactions

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

⚠️ grid-openapi studio · code · diff

There was a regression in your SDK.
generate ❗ (prev: generate ✅)

New diagnostics (26 error, 1 warning, 13 note)
Reference/NotFound: Ignored reference `#/components/schemas/BrlExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/DkkExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/GbpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/HkdExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/IdrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/InrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MxnExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MyrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/PhpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/SgdExternalAccountInfo` (not found in spec).
⚠️ grid-typescript studio · code · diff

There was a regression in your SDK.
generate ❗ (prev: generate ✅) → build ✅lint ✅test ✅

npm install https://pkg.stainless.com/s/grid-typescript/d8c7da3843f81278f396db6142b450d662857824/dist.tar.gz
New diagnostics (26 error, 1 warning, 13 note)
Reference/NotFound: Ignored reference `#/components/schemas/BrlExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/DkkExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/GbpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/HkdExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/IdrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/InrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MxnExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MyrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/PhpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/SgdExternalAccountInfo` (not found in spec).
⚠️ grid-python studio · code · diff

There was a regression in your SDK.
generate ❗ (prev: generate ✅) → build ⏳lint ⏳test ⏳

New diagnostics (26 error, 1 warning, 13 note)
Reference/NotFound: Ignored reference `#/components/schemas/BrlExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/DkkExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/GbpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/HkdExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/IdrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/InrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MxnExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MyrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/PhpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/SgdExternalAccountInfo` (not found in spec).
⚠️ grid-kotlin studio · code · diff

There was a regression in your SDK.
generate ❗ (prev: generate ✅) → build ✅lint ✅test ✅

New diagnostics (26 error, 1 warning, 3 note)
Reference/NotFound: Ignored reference `#/components/schemas/BrlExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/DkkExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/GbpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/HkdExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/IdrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/InrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MxnExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/MyrExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/PhpExternalAccountInfo` (not found in spec).
Reference/NotFound: Ignored reference `#/components/schemas/SgdExternalAccountInfo` (not found in spec).

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-02-19 19:52:40 UTC

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 18, 2026

Greptile Summary

Adds complete CRUD API for platform fee rules, enabling Grid platforms to configure per-transaction-type markup layered on top of Lightspark and counterparty fees. The implementation extends existing rate details schemas to surface platform fees in quotes and transactions, adds five new endpoints under /fee-rules, and includes comprehensive documentation across all four use-case tabs.

Key additions:

  • New endpoints: POST/GET /fee-rules, GET/PATCH/DELETE /fee-rules/{feeRuleId}, GET /fee-rules/report
  • Fee rule schemas supporting FIXED, PERCENTAGE, and HYBRID fee types with validation constraints (max $100 fixed, max 20% variable)
  • Extensions to IncomingRateDetails and OutgoingRateDetails with three optional platform fee fields
  • Error codes: INVALID_FEE_RULE, INVALID_MONTH_FORMAT, FEE_RULE_NOT_FOUND, FEE_RULE_EXISTS
  • Shared Mintlify documentation snippet with cURL examples and constraints documentation

Consistency with existing patterns:

  • Uses same conventions as existing Grid API fee fields (gridApiFixedFee, gridApiVariableFeeRate)
  • Follows repository structure (edit in openapi/, bundle to root)
  • Proper MDX frontmatter and snippet reuse across use-case tabs
  • Matches existing path ordering pattern (parameterized before literal paths)

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk once the missing maximum constraint is added
  • The implementation is comprehensive, well-documented, and follows existing repository patterns consistently. One syntax issue needs fixing (missing maximum constraint on FeeRule.fixedFee), and there are a couple of style suggestions about documentation clarity and path ordering that match existing patterns in the codebase. The API design is sound with appropriate validation, error codes, and examples.
  • openapi/components/schemas/fee_rules/FeeRule.yaml requires the missing maximum constraint. Other files are well-structured.

Important Files Changed

Filename Overview
openapi/components/schemas/fee_rules/FeeRule.yaml Core fee rule schema definition with proper types and constraints; missing maximum constraint on fixedFee (present in request schemas but not response)
openapi/paths/fee-rules/fee_rules.yaml Well-documented POST and GET endpoints with clear examples and comprehensive error responses
openapi/paths/fee-rules/fee_rules_{feeRuleId}.yaml Complete CRUD operations for individual fee rules with appropriate HTTP methods and response codes
openapi/components/schemas/transactions/IncomingRateDetails.yaml Extends existing schema with three new optional platform fee fields, maintaining consistency with existing grid API fee fields
openapi/components/schemas/transactions/OutgoingRateDetails.yaml Extends existing schema with three new optional platform fee fields, maintaining consistency with existing grid API fee fields
mintlify/snippets/platform-fee-rules.mdx Comprehensive documentation with clear examples, proper MDX structure, and accurate example data matching the OpenAPI spec
openapi/openapi.yaml Main spec file with new fee-rules paths added; literal path /fee-rules/report appears after parameterized /{feeRuleId} which may cause routing issues

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Platform creates FeeRule] --> B{POST /fee-rules}
    B --> C[Validate transactionType & feeType]
    C --> D{Check duplicate}
    D -->|Exists| E[409 FEE_RULE_EXISTS]
    D -->|New| F{Validate fee amounts}
    F -->|Invalid| G[400 INVALID_FEE_RULE]
    F -->|Valid| H[Create FeeRule entity]
    H --> I[Return 201 with FeeRule]
    
    J[Customer requests quote] --> K[Evaluate active FeeRules]
    K --> L{Matching rule for txn type?}
    L -->|Yes| M[Calculate platform fees]
    L -->|No| N[No platform fees]
    M --> O[Include in rateDetails]
    N --> O
    O --> P[Return quote with platformFixedFee, platformVariableFeeRate, platformVariableFeeAmount]
    
    Q[Transaction settles] --> R[Collect platform fees]
    R --> S[Credit platform subledger]
    
    T[Platform requests report] --> U{GET /fee-rules/report?month=YYYY-MM}
    U --> V{Valid month format?}
    V -->|No| W[400 INVALID_MONTH_FORMAT]
    V -->|Yes| X[Aggregate fees by transaction type]
    X --> Y[Return FeeReport with lines]
Loading

Last reviewed commit: 9a66dbe

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

24 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 131 to 149
{
"month": "2026-02",
"totalPlatformFeesCollected": 128450,
"currency": "USD",
"lines": [
{
"transactionType": "CROSS_BORDER_PAYOUT",
"transactionCount": 97,
"platformFeesCollected": 51300,
"currency": "USD"
},
{
"transactionType": "TRANSFER_OUT",
"transactionCount": 245,
"platformFeesCollected": 62500,
"currency": "USD"
}
]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Fee report example total doesn't match line items

The totalPlatformFeesCollected is 128,450 but the two line items sum to only 113,800 (51,300 + 62,500). The OpenAPI example in fee_rules_report.yaml includes a third RAMP_OFF line (14,650) that makes the total correct — but the documentation snippet is missing that line.

Either add the missing RAMP_OFF line to match the total, or adjust totalPlatformFeesCollected to 113,800.

Suggested change
{
"month": "2026-02",
"totalPlatformFeesCollected": 128450,
"currency": "USD",
"lines": [
{
"transactionType": "CROSS_BORDER_PAYOUT",
"transactionCount": 97,
"platformFeesCollected": 51300,
"currency": "USD"
},
{
"transactionType": "TRANSFER_OUT",
"transactionCount": 245,
"platformFeesCollected": 62500,
"currency": "USD"
}
]
}
```json 200 OK
{
"month": "2026-02",
"totalPlatformFeesCollected": 128450,
"currency": "USD",
"lines": [
{
"transactionType": "CROSS_BORDER_PAYOUT",
"transactionCount": 97,
"platformFeesCollected": 51300,
"currency": "USD"
},
{
"transactionType": "TRANSFER_OUT",
"transactionCount": 245,
"platformFeesCollected": 62500,
"currency": "USD"
},
{
"transactionType": "RAMP_OFF",
"transactionCount": 58,
"platformFeesCollected": 14650,
"currency": "USD"
}
]
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/snippets/platform-fee-rules.mdx
Line: 131-149

Comment:
**Fee report example total doesn't match line items**

The `totalPlatformFeesCollected` is 128,450 but the two line items sum to only 113,800 (51,300 + 62,500). The OpenAPI example in `fee_rules_report.yaml` includes a third `RAMP_OFF` line (14,650) that makes the total correct — but the documentation snippet is missing that line.

Either add the missing `RAMP_OFF` line to match the total, or adjust `totalPlatformFeesCollected` to 113,800.

```suggestion
```json 200 OK
{
  "month": "2026-02",
  "totalPlatformFeesCollected": 128450,
  "currency": "USD",
  "lines": [
    {
      "transactionType": "CROSS_BORDER_PAYOUT",
      "transactionCount": 97,
      "platformFeesCollected": 51300,
      "currency": "USD"
    },
    {
      "transactionType": "TRANSFER_OUT",
      "transactionCount": 245,
      "platformFeesCollected": 62500,
      "currency": "USD"
    },
    {
      "transactionType": "RAMP_OFF",
      "transactionCount": 58,
      "platformFeesCollected": 14650,
      "currency": "USD"
    }
  ]
}
```

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

@@ -0,0 +1,164 @@
import { gridBaseUrl } from '/snippets/variables.mdx';
Copy link
Contributor

Choose a reason for hiding this comment

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

Unused import: gridBaseUrl

gridBaseUrl is imported but never used in this file — the cURL examples hardcode https://api.lightspark.com/grid/2025-10-13 directly. This is consistent with other snippet files (none of them actually use gridBaseUrl in code blocks), so consider removing the unused import.

Suggested change
import { gridBaseUrl } from '/snippets/variables.mdx';
Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/snippets/platform-fee-rules.mdx
Line: 1

Comment:
**Unused import: `gridBaseUrl`**

`gridBaseUrl` is imported but never used in this file — the cURL examples hardcode `https://api.lightspark.com/grid/2025-10-13` directly. This is consistent with other snippet files (none of them actually use `gridBaseUrl` in code blocks), so consider removing the unused import.

```suggestion
```

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

Comment on lines 94 to 99
/fee-rules:
$ref: paths/fee-rules/fee_rules.yaml
/fee-rules/{feeRuleId}:
$ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml
/fee-rules/report:
$ref: paths/fee-rules/fee_rules_report.yaml
Copy link
Contributor

Choose a reason for hiding this comment

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

Literal path /fee-rules/report ordered after parameterized /fee-rules/{feeRuleId}

/fee-rules/{feeRuleId} appears before /fee-rules/report. While OpenAPI 3.x says path ordering doesn't determine routing, many code generators and API gateways use first-match-wins semantics — which means /fee-rules/report could be matched by the {feeRuleId} parameter, with "report" captured as the ID.

This is the same pattern already present with /customers/{customerId} before /customers/kyc-link, so it may be intentional for this repo. But if any consumer relies on YAML ordering, swapping the literal path above the parameterized one would be safer:

Suggested change
/fee-rules:
$ref: paths/fee-rules/fee_rules.yaml
/fee-rules/{feeRuleId}:
$ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml
/fee-rules/report:
$ref: paths/fee-rules/fee_rules_report.yaml
/fee-rules:
$ref: paths/fee-rules/fee_rules.yaml
/fee-rules/report:
$ref: paths/fee-rules/fee_rules_report.yaml
/fee-rules/{feeRuleId}:
$ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/openapi.yaml
Line: 94-99

Comment:
**Literal path `/fee-rules/report` ordered after parameterized `/fee-rules/{feeRuleId}`**

`/fee-rules/{feeRuleId}` appears before `/fee-rules/report`. While OpenAPI 3.x says path ordering doesn't determine routing, many code generators and API gateways use first-match-wins semantics — which means `/fee-rules/report` could be matched by the `{feeRuleId}` parameter, with `"report"` captured as the ID.

This is the same pattern already present with `/customers/{customerId}` before `/customers/kyc-link`, so it may be intentional for this repo. But if any consumer relies on YAML ordering, swapping the literal path above the parameterized one would be safer:

```suggestion
  /fee-rules:
    $ref: paths/fee-rules/fee_rules.yaml
  /fee-rules/report:
    $ref: paths/fee-rules/fee_rules_report.yaml
  /fee-rules/{feeRuleId}:
    $ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml
```

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

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

24 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +35 to +38
description: >-
Variable fee as a decimal rate of the transaction amount
(e.g., 0.005 = 0.5%). Applied to the sending amount at quote creation.
Required when feeType is PERCENTAGE or HYBRID.
Copy link
Contributor

Choose a reason for hiding this comment

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

variableFeeRate description is misleading for incoming transactions

The description says "Applied to the sending amount at quote creation," but this is only accurate for outgoing transactions. For incoming transactions (TRANSFER_IN, RAMP_ON), the IncomingRateDetails.platformVariableFeeAmount description says it's applied to the receiving amount — matching how the existing gridApiVariableFeeRate works in that context.

Consider using direction-neutral language like "Applied to the transaction amount at quote creation" to avoid confusing consumers who read both this schema and the rate details.

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/fee_rules/FeeRule.yaml
Line: 35-38

Comment:
**`variableFeeRate` description is misleading for incoming transactions**

The description says "Applied to the sending amount at quote creation," but this is only accurate for outgoing transactions. For incoming transactions (`TRANSFER_IN`, `RAMP_ON`), the `IncomingRateDetails.platformVariableFeeAmount` description says it's applied to the *receiving* amount — matching how the existing `gridApiVariableFeeRate` works in that context.

Consider using direction-neutral language like "Applied to the transaction amount at quote creation" to avoid confusing consumers who read both this schema and the rate details.

<sub>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!</sub>

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

Comment on lines +24 to +30
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
Copy link
Contributor

Choose a reason for hiding this comment

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

fixedFee missing maximum constraint in response schema

The FeeRuleCreateRequest and FeeRulePatchRequest schemas both specify maximum: 10000 for fixedFee, but this response schema omits it. Meanwhile, variableFeeRate (line 40) does have maximum: 0.20 here. Code generators that derive validation from the response schema (e.g., for round-trip testing or SDK type constraints) would not enforce the $100 cap on this field.

Suggested change
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
maximum: 10000
example: 150
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/fee_rules/FeeRule.yaml
Line: 24-30

Comment:
**`fixedFee` missing `maximum` constraint in response schema**

The `FeeRuleCreateRequest` and `FeeRulePatchRequest` schemas both specify `maximum: 10000` for `fixedFee`, but this response schema omits it. Meanwhile, `variableFeeRate` (line 40) does have `maximum: 0.20` here. Code generators that derive validation from the response schema (e.g., for round-trip testing or SDK type constraints) would not enforce the $100 cap on this field.

```suggestion
  fixedFee:
    type: integer
    format: int64
    description: >-
      Fixed fee in the smallest unit of USD (cents). Applied per transaction.
      Required when feeType is FIXED or HYBRID.
    minimum: 0
    maximum: 10000
    example: 150
```

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

jaymantri and others added 2 commits February 19, 2026 11:41
Introduce a complete CRUD API for platform-configurable fee markup,
enabling platforms to define per-transaction-type fees that layer on
top of Lightspark and counterparty fees.

New endpoints:
- POST /fee-rules — create a fee rule (one per transaction type)
- GET /fee-rules — list all fee rules with optional filters
- GET /fee-rules/{feeRuleId} — retrieve a single rule
- PATCH /fee-rules/{feeRuleId} — partial update (amounts, enabled)
- DELETE /fee-rules/{feeRuleId} — remove a rule
- GET /fee-rules/report — monthly aggregated fee revenue

New schemas:
- FeeRule, FeeTransactionType, FeeRuleType
- FeeRuleCreateRequest, FeeRulePatchRequest
- FeeReport, FeeReportLine

Extended existing schemas:
- OutgoingRateDetails and IncomingRateDetails gain platform fee
  fields (platformFixedFee, platformVariableFeeRate,
  platformVariableFeeAmount) so quotes and transactions surface the
  platform markup alongside Lightspark fees.

New error codes:
- INVALID_FEE_RULE (400), INVALID_MONTH_FORMAT (400)
- FEE_RULE_NOT_FOUND (404), FEE_RULE_EXISTS (409)

Documentation:
- Shared snippet with guide, cURL examples, and fee layering table
- Wrapper pages in all four use-case tabs (Payouts, Ramps, Rewards,
  Global P2P) under Platform Tools

Co-authored-by: Cursor <cursoragent@cursor.com>
- Rename operationId from listFeeRules to getFeeRules to avoid
  Stainless auto-detecting the endpoint as paginated (matches the
  getExchangeRates convention for non-paginated collections)
- Reorder paths: /fee-rules/report before /fee-rules/{feeRuleId}
  so the literal path precedes the parameterized one
- Add missing RAMP_OFF line item to the doc snippet fee report
  example so the total (128,450) matches the sum of line items
- Remove unused gridBaseUrl import from the snippet

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

24 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +24 to +30
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
Copy link
Contributor

Choose a reason for hiding this comment

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

maximum: 10000 constraint missing in response schema

The FeeRuleCreateRequest and FeeRulePatchRequest schemas both enforce maximum: 10000 for fixedFee, but this response schema omits it. Meanwhile, variableFeeRate on line 40 does include maximum: 0.20. Code generators deriving validation from response schemas won't enforce the $100 cap.

Suggested change
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
fixedFee:
type: integer
format: int64
description: >-
Fixed fee in the smallest unit of USD (cents). Applied per transaction.
Required when feeType is FIXED or HYBRID.
minimum: 0
maximum: 10000
example: 150
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/fee_rules/FeeRule.yaml
Line: 24-30

Comment:
`maximum: 10000` constraint missing in response schema

The `FeeRuleCreateRequest` and `FeeRulePatchRequest` schemas both enforce `maximum: 10000` for `fixedFee`, but this response schema omits it. Meanwhile, `variableFeeRate` on line 40 does include `maximum: 0.20`. Code generators deriving validation from response schemas won't enforce the $100 cap.

```suggestion
  fixedFee:
    type: integer
    format: int64
    description: >-
      Fixed fee in the smallest unit of USD (cents). Applied per transaction.
      Required when feeType is FIXED or HYBRID.
    minimum: 0
    maximum: 10000
    example: 150
```

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

Comment on lines +35 to +37
description: >-
Variable fee as a decimal rate of the transaction amount
(e.g., 0.005 = 0.5%). Applied to the sending amount at quote creation.
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using direction-neutral language for variableFeeRate description. Currently says "Applied to the sending amount" but for incoming transactions it's applied to the receiving amount.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/fee_rules/FeeRule.yaml
Line: 35-37

Comment:
Consider using direction-neutral language for `variableFeeRate` description. Currently says "Applied to the sending amount" but for incoming transactions it's applied to the receiving amount.

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

Comment on lines +94 to +99
/fee-rules:
$ref: paths/fee-rules/fee_rules.yaml
/fee-rules/report:
$ref: paths/fee-rules/fee_rules_report.yaml
/fee-rules/{feeRuleId}:
$ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider if literal path /fee-rules/report should appear before parameterized /{feeRuleId} to avoid potential routing conflicts in code generators. This pattern matches existing /customers paths so may be intentional.

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/openapi.yaml
Line: 94-99

Comment:
Consider if literal path `/fee-rules/report` should appear before parameterized `/{feeRuleId}` to avoid potential routing conflicts in code generators. This pattern matches existing `/customers` paths so may be intentional.

<sub>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!</sub>

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

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