Skip to content

feat: adding openapi schema for fx api#158

Open
pengying wants to merge 1 commit intomainfrom
02-05-feat_adding_openapi_schema_for_fx_api
Open

feat: adding openapi schema for fx api#158
pengying wants to merge 1 commit intomainfrom
02-05-feat_adding_openapi_schema_for_fx_api

Conversation

@pengying
Copy link
Contributor

@pengying pengying commented Feb 6, 2026

TL;DR

Added new Exchange Rates API endpoint to retrieve cached foreign exchange rates with platform-specific fees.

What changed?

  • Added a new /exchange-rates endpoint that provides cached FX rates
  • Created new tag "Exchange Rates" in the OpenAPI specification
  • Added new schemas for exchange rate data:
    • ExchangeRate - Contains source/destination currency details, payment rails, amounts, rates, and fees
    • ExchangeRateFees - Defines fee structure for exchange rates
  • Moved the Currency schema definition to avoid duplication
  • Added query parameters for filtering:
    • sourceCurrency (required)
    • destinationCurrency (optional, can specify multiple)
    • sendingAmount (optional)

GET request to /exchange-rates with the required sourceCurrency parameter:

GET /exchange-rates?sourceCurrency=USD

Optional parameters:

  • Filter by specific destination currencies: &destinationCurrency=INR&destinationCurrency=GBP
  • Specify sending amount: &sendingAmount=20000

Copy link
Contributor Author

pengying commented Feb 6, 2026

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

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

✱ Stainless preview builds

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

feat: adding openapi schema for fx api

Edit this comment to update it. It will appear in the SDK's changelogs.

grid-typescript studio · code · diff

Your SDK built successfully.
generate ✅build ❗lint ❗test ✅

grid-kotlin studio · code · diff

Your SDK built successfully.
generate ✅build ❗lint ✅test ❗

grid-openapi studio · code · diff

Your SDK built successfully.
generate ✅


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-06 01:29:54 UTC

@pengying pengying marked this pull request as ready for review February 6, 2026 00:34
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Greptile Overview

Greptile Summary

Adds a new Exchange Rates tag and a GET /exchange-rates endpoint to the OpenAPI spec, including new ExchangeRate and ExchangeRateFees schemas and wiring the path into the split spec (openapi/openapi.yaml). The endpoint is documented as returning cached FX corridor rates (with platform-specific fees) and supports query filtering by sourceCurrency, optional repeated destinationCurrency, and optional sendingAmount.

Key merge-blocker: the /exchange-rates response examples are internally inconsistent (the receivingAmount values don’t match sendingAmount * exchangeRate), which will mislead docs/SDK consumers and break contract expectations.

Confidence Score: 2/5

  • Not safe to merge until examples/schema correctness are fixed.
  • The new endpoint wiring is straightforward, but the published response examples are mathematically inconsistent with the documented exchangeRate semantics, and Currency being entirely optional will generate incorrect SDK types if those fields are required in practice.
  • openapi/paths/exchange-rates/exchange_rates.yaml; openapi/components/schemas/common/Currency.yaml (and any bundled copies regenerated from the split spec)

Important Files Changed

Filename Overview
openapi/components/schemas/exchange_rates/ExchangeRate.yaml New ExchangeRate schema added with inconsistent exchangeRate description vs Quote schema, incorrect example calculations (values ~2x expected), and ambiguous sendingAmount optionality
openapi/components/schemas/exchange_rates/ExchangeRateFees.yaml New ExchangeRateFees schema added with missing required field specification for the 'fixed' property
openapi/paths/exchange-rates/exchange_rates.yaml New GET /exchange-rates endpoint with mathematically incorrect example values (receivingAmount ~2x expected based on exchangeRate) and unclear default parameter behavior
.github/workflows/stainless-action.yml New Stainless SDK generation workflow added with proper PR lifecycle triggers and OIDC permissions
openapi/openapi.yaml Main OpenAPI spec updated to reference new /exchange-rates endpoint and Exchange Rates tag
mintlify/openapi.yaml Bundled OpenAPI spec updated with new /exchange-rates endpoint and schemas; contains incorrect example math for receivingAmount vs exchangeRate/sendingAmount.
openapi.yaml Bundled root OpenAPI spec updated with /exchange-rates and schema moves; includes inconsistent example values (receivingAmount does not match exchangeRate*sendingAmount).

Sequence Diagram

sequenceDiagram
  autonumber
  participant Client
  participant GridAPI as GRID API
  participant Cache as FX Cache (~5m)

  Client->>GridAPI: GET /exchange-rates?sourceCurrency=USD&destinationCurrency=INR&sendingAmount=10000
  GridAPI->>Cache: Lookup cached FX corridors by filters
  Cache-->>GridAPI: Cached rates + platform fees + updatedAt
  GridAPI-->>Client: 200 { data: [ExchangeRate...] }

  Note over Client,GridAPI: Response items include corridor rails, exchangeRate, receivingAmount, fees, updatedAt
Loading

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.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@pengying pengying force-pushed the 02-05-feat_adding_openapi_schema_for_fx_api branch from 8f92946 to 3fecd5a Compare February 6, 2026 00:44
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.

7 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Additional Comments (1)

openapi.yaml
Generated file edited

Per CLAUDE.md, openapi.yaml at repo root is a bundled artifact and should not be edited manually; changes should be made in openapi/** and then bundled (which also updates mintlify/openapi.yaml). Editing the generated file directly will be overwritten on the next build and can drift from the split source of truth.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi.yaml
Line: 4113:4115

Comment:
**Generated file edited**

Per `CLAUDE.md`, `openapi.yaml` at repo root is a bundled artifact and should not be edited manually; changes should be made in `openapi/**` and then bundled (which also updates `mintlify/openapi.yaml`). Editing the generated file directly will be overwritten on the next build and can drift from the split source of truth.

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

@pengying pengying force-pushed the 02-05-feat_adding_openapi_schema_for_fx_api branch 2 times, most recently from 5c32c0c to c80209d Compare February 6, 2026 00:55
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.

7 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Additional Comments (2)

openapi.yaml
Generated spec edited directly
Per CLAUDE.md, the repo-root openapi.yaml is a bundled artifact generated from openapi/** via npm run build:openapi. Editing it directly will be overwritten and can drift from the split spec. The fix is to update only the split spec under openapi/** and re-bundle so this file is produced by the build.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi.yaml
Line: 1:3

Comment:
**Generated spec edited directly**
Per `CLAUDE.md`, the repo-root `openapi.yaml` is a bundled artifact generated from `openapi/**` via `npm run build:openapi`. Editing it directly will be overwritten and can drift from the split spec. The fix is to update only the split spec under `openapi/**` and re-bundle so this file is produced by the build.

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

mintlify/openapi.yaml
Generated spec edited directly
mintlify/openapi.yaml is also a bundled copy of the OpenAPI spec and will be overwritten when the spec is rebuilt. Changes should be made in the split spec under openapi/** and then re-bundled, rather than editing this file by hand.

Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/openapi.yaml
Line: 1:3

Comment:
**Generated spec edited directly**
`mintlify/openapi.yaml` is also a bundled copy of the OpenAPI spec and will be overwritten when the spec is rebuilt. Changes should be made in the split spec under `openapi/**` and then re-bundled, rather than editing this file by hand.

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.

7 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Additional Comments (1)

.github/workflows/stainless-action.yml
Inconsistent Stainless config detection

guess_config: true is set for the preview job but not for the merge job. If Stainless needs config guessing for this repo, merge builds can fail even when preview builds pass. Either add guess_config: true to the merge step as well, or remove it from preview if it’s not required.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/stainless-action.yml
Line: 34:41

Comment:
**Inconsistent Stainless config detection**

`guess_config: true` is set for the preview job but not for the merge job. If Stainless needs config guessing for this repo, merge builds can fail even when preview builds pass. Either add `guess_config: true` to the merge step as well, or remove it from preview if it’s not required.

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

@pengying pengying force-pushed the 02-05-feat_adding_openapi_schema_for_fx_api branch from c80209d to 0527518 Compare February 6, 2026 00:59
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.

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@pengying pengying force-pushed the 02-05-feat_adding_openapi_schema_for_fx_api branch from 0527518 to 9d4e3c1 Compare February 6, 2026 01:22
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.

7 files reviewed, 8 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +36 to +40
exchangeRate:
type: number
description: Number of destination currency units per sending currency unit
exclusiveMinimum: 0
example: 82.50
Copy link
Contributor

Choose a reason for hiding this comment

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

Incorrect or inconsistent exchangeRate description

The description states "Number of destination currency units per sending currency unit", but this conflicts with the Quote schema (Quote.yaml line 70) which describes exchangeRate as "Number of sending currency units per receiving currency unit" - these are mathematical inverses.

Additionally, the example values don't match the calculation:

  • Example 1: sendingAmount=10000 (100 USD), exchangeRate=82.5, but receivingAmount=1650000 (16500 INR). Expected: 100 USD * 82.5 = 8250 INR (825000 paise)
  • Example 2: sendingAmount=10000 (100 USD), exchangeRate=0.925, but receivingAmount=18500 (185 EUR). Expected: 100 USD * 0.925 = 92.5 EUR (9250 cents)

The calculations in the examples are off by approximately 2x. Either the examples or the rate description needs correction to ensure SDK users understand the correct calculation.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/exchange_rates/ExchangeRate.yaml
Line: 36:40

Comment:
**Incorrect or inconsistent `exchangeRate` description**

The description states "Number of destination currency units per sending currency unit", but this conflicts with the Quote schema (Quote.yaml line 70) which describes exchangeRate as "Number of sending currency units per receiving currency unit" - these are mathematical inverses.

Additionally, the example values don't match the calculation:
- Example 1: sendingAmount=10000 (100 USD), exchangeRate=82.5, but receivingAmount=1650000 (16500 INR). Expected: 100 USD * 82.5 = 8250 INR (825000 paise)
- Example 2: sendingAmount=10000 (100 USD), exchangeRate=0.925, but receivingAmount=18500 (185 EUR). Expected: 100 USD * 0.925 = 92.5 EUR (9250 cents)

The calculations in the examples are off by approximately 2x. Either the examples or the rate description needs correction to ensure SDK users understand the correct calculation.

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

Comment on lines +71 to +107
decimals: 2
name: US Dollar
symbol: "$"
sourcePaymentRail: RTP
sendingAmount: 10000
destinationCurrency:
code: INR
decimals: 2
name: Indian Rupee
symbol: "₹"
destinationPaymentRail: UPI
receivingAmount: 1650000
exchangeRate: 82.50
fees:
fixed: 100
updatedAt: "2025-02-05T12:00:00Z"
- sourceCurrency:
code: USD
decimals: 2
name: US Dollar
symbol: "$"
sourcePaymentRail: RTP
sendingAmount: 10000
destinationCurrency:
code: EUR
decimals: 2
name: Euro
symbol: "€"
destinationPaymentRail: SEPA_INSTANT
receivingAmount: 18500
exchangeRate: 0.925
fees:
fixed: 10
updatedAt: "2025-02-05T12:00:00Z"
"400":
description: Bad request - Invalid parameters
content:
Copy link
Contributor

Choose a reason for hiding this comment

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

Example values don't match schema calculations

The example response shows mathematically inconsistent values:

USD to INR example:

  • Sending: 10000 cents (100 USD)
  • Rate: 82.5 (per description: "82.5 INR per 1 USD")
  • Fees: 100 cents (1 USD)
  • Receiving: 1650000 paise (16500 INR) ❌

Expected calculation: (10000 - 100) * 82.5 / 100 = 8167.5 INR or 10000 * 82.5 / 100 = 8250 INR

USD to EUR example:

  • Sending: 10000 cents (100 USD)
  • Rate: 0.925
  • Receiving: 18500 cents (185 EUR) ❌

Expected: 10000 * 0.925 = 9250 cents (92.5 EUR)

The receivingAmount values appear to be approximately 2x what the exchangeRate suggests. Please verify the calculation logic or correct the examples to match the actual API behavior.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/paths/exchange-rates/exchange_rates.yaml
Line: 71:107

Comment:
**Example values don't match schema calculations**

The example response shows mathematically inconsistent values:

**USD to INR example:**
- Sending: 10000 cents (100 USD)
- Rate: 82.5 (per description: "82.5 INR per 1 USD")
- Fees: 100 cents (1 USD)
- Receiving: 1650000 paise (16500 INR) ❌

Expected calculation: `(10000 - 100) * 82.5 / 100 = 8167.5 INR` or `10000 * 82.5 / 100 = 8250 INR`

**USD to EUR example:**
- Sending: 10000 cents (100 USD)
- Rate: 0.925
- Receiving: 18500 cents (185 EUR) ❌

Expected: `10000 * 0.925 = 9250 cents (92.5 EUR)`

The receivingAmount values appear to be approximately 2x what the exchangeRate suggests. Please verify the calculation logic or correct the examples to match the actual API behavior.

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

Comment on lines +42 to +51
required: false
schema:
type: integer
format: int64
minimum: 0
default: 10000
example: 10000
responses:
"200":
description: Successful operation
Copy link
Contributor

Choose a reason for hiding this comment

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

Query parameter default value without proper documentation

The sendingAmount parameter has default: 10000 in the schema, but OpenAPI 3.1 default values for query parameters don't automatically get applied by clients - they're documentation-only.

The description should clarify what happens when this parameter is omitted:

  • Does the server use 10000 as the default?
  • Does it return rates without calculated receiving amounts?
  • Does it return an error?
Suggested change
required: false
schema:
type: integer
format: int64
minimum: 0
default: 10000
example: 10000
responses:
"200":
description: Successful operation
description: Sending amount in the smallest unit of the source currency (e.g., cents for USD). If not provided, rates are returned with a default calculation based on 10000 units (e.g., 100.00 in major currency).
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/paths/exchange-rates/exchange_rates.yaml
Line: 42:51

Comment:
**Query parameter `default` value without proper documentation**

The `sendingAmount` parameter has `default: 10000` in the schema, but OpenAPI 3.1 default values for query parameters don't automatically get applied by clients - they're documentation-only. 

The description should clarify what happens when this parameter is omitted:
- Does the server use 10000 as the default?
- Does it return rates without calculated receiving amounts?
- Does it return an error?

```suggestion
      description: Sending amount in the smallest unit of the source currency (e.g., cents for USD). If not provided, rates are returned with a default calculation based on 10000 units (e.g., 100.00 in major currency).
```

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

Comment on lines +18 to +23
sendingAmount:
type: integer
format: int64
description: The sending amount in the smallest unit of the source currency (e.g., cents for USD). Echoed back from the request if provided.
minimum: 0
example: 10000
Copy link
Contributor

Choose a reason for hiding this comment

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

Clarification needed: when is sendingAmount included in response?

The description states "Echoed back from the request if provided" but sendingAmount is not in the required array (line 3-10). This means:

  1. If a client doesn't provide sendingAmount in the query param, the response won't include this field
  2. SDK generators will make this optional in response types

However, the parameter schema has default: 10000, which suggests a default is applied. Consider:

  • If the server always calculates with a default, add sendingAmount to the required array
  • If truly optional, clarify in the description what the receivingAmount represents when sendingAmount is omitted
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/exchange_rates/ExchangeRate.yaml
Line: 18:23

Comment:
**Clarification needed: when is `sendingAmount` included in response?**

The description states "Echoed back from the request if provided" but `sendingAmount` is not in the `required` array (line 3-10). This means:

1. If a client doesn't provide `sendingAmount` in the query param, the response won't include this field
2. SDK generators will make this optional in response types

However, the parameter schema has `default: 10000`, which suggests a default is applied. Consider:
- If the server always calculates with a default, add `sendingAmount` to the required array
- If truly optional, clarify in the description what the receivingAmount represents when sendingAmount is omitted

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

Comment on lines +82 to +86
receivingAmount: 1650000
exchangeRate: 82.50
fees:
fixed: 100
updatedAt: "2025-02-05T12:00:00Z"
Copy link
Contributor

Choose a reason for hiding this comment

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

Incorrect example math

In the 200-response example, sendingAmount: 10000 (=$100) and exchangeRate: 82.50 imply a receiving amount of 10000 * 82.5 = 825000 (in paise) before fees, but the example shows receivingAmount: 1650000 (double). This makes the example internally inconsistent and will mislead SDK/docs consumers. The EUR example below has the same issue (10000 * 0.925 = 9250, but example shows 18500).

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/paths/exchange-rates/exchange_rates.yaml
Line: 82:86

Comment:
**Incorrect example math**

In the 200-response example, `sendingAmount: 10000` (=$100) and `exchangeRate: 82.50` imply a receiving amount of `10000 * 82.5 = 825000` (in paise) before fees, but the example shows `receivingAmount: 1650000` (double). This makes the example internally inconsistent and will mislead SDK/docs consumers. The EUR example below has the same issue (`10000 * 0.925 = 9250`, but example shows `18500`).

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Additional Comments (3)

openapi/components/schemas/common/Currency.yaml
Missing required fields in Currency schema

The Currency schema has no required field list, which means SDK generators will treat all properties (code, name, symbol, decimals) as optional. However, all examples throughout the codebase populate all four fields, suggesting they should be required for consistent API behavior.

For SDK generator compatibility (especially Stainless which is configured in this PR), consider adding:

required:
  - code
  - name
  - symbol
  - decimals

This ensures generated SDKs properly validate Currency objects and prevents runtime errors from missing required fields.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/Currency.yaml
Line: 1:23

Comment:
**Missing `required` fields in Currency schema**

The Currency schema has no `required` field list, which means SDK generators will treat all properties (code, name, symbol, decimals) as optional. However, all examples throughout the codebase populate all four fields, suggesting they should be required for consistent API behavior.

For SDK generator compatibility (especially Stainless which is configured in this PR), consider adding:
```yaml
required:
  - code
  - name
  - symbol
  - decimals
```

This ensures generated SDKs properly validate Currency objects and prevents runtime errors from missing required fields.

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

openapi/components/schemas/exchange_rates/ExchangeRateFees.yaml
Missing required field for ExchangeRateFees

The ExchangeRateFees schema only has one property (fixed) but doesn't specify if it's required. Since fees are a required part of ExchangeRate (line 9 of ExchangeRate.yaml), and the schema is specifically for "fees associated with an exchange rate", the fixed field should likely be required.

Consider adding:

required:
  - fixed

Or if fixed fees are truly optional (e.g., when only variable fees apply), add documentation explaining when this field may be absent.

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/exchange_rates/ExchangeRateFees.yaml
Line: 1:10

Comment:
**Missing `required` field for ExchangeRateFees**

The ExchangeRateFees schema only has one property (`fixed`) but doesn't specify if it's required. Since fees are a required part of ExchangeRate (line 9 of ExchangeRate.yaml), and the schema is specifically for "fees associated with an exchange rate", the `fixed` field should likely be required.

Consider adding:
```yaml
required:
  - fixed
```

Or if `fixed` fees are truly optional (e.g., when only variable fees apply), add documentation explaining when this field may be absent.

<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.

openapi/components/schemas/common/Currency.yaml
All fields optional in SDKs

Currency doesn’t declare a required: list, so code generators will treat code/name/symbol/decimals as optional even though your examples (and typical currency objects) always include them. If these fields are always present in API responses, mark them as required to avoid generating weaker/incorrect SDK types.

Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/Currency.yaml
Line: 1:3

Comment:
**All fields optional in SDKs**

`Currency` doesn’t declare a `required:` list, so code generators will treat `code/name/symbol/decimals` as optional even though your examples (and typical currency objects) always include them. If these fields are always present in API responses, mark them as required to avoid generating weaker/incorrect SDK types.

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.

3 participants