Skip to content

Conversation

@pengying
Copy link
Contributor

@pengying pengying commented Jan 22, 2026

Summary of API Changes in Branch peng-stainless_init

This branch contains significant OpenAPI schema changes primarily focused on improving SDK generation compatibility (likely for Stainless SDK). The main themes are:

  1. Adding discriminators to polymorphic types (oneOf schemas)
  2. Converting enum: [SINGLE_VALUE] to const: SINGLE_VALUE for single-value enums
  3. Extracting inline schemas into separate reusable components
  4. Renaming Error to GridError to avoid naming conflicts
  5. Minor field changes and fixes

Detailed API Changes with JSON Examples

1. Quote Request - Destination Discriminator Added

Before: Destination was a oneOf without a discriminator
After: Added destinationType discriminator field

// Account destination
{
  "destinationType": "ACCOUNT",
  "accountId": "a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
  "currency": "EUR"
}

// UMA Address destination
{
  "destinationType": "UMA_ADDRESS",
  "umaAddress": "$receiver@uma.domain.com",
  "currency": "EUR"
}

// External Account Details destination
{
  "destinationType": "EXTERNAL_ACCOUNT_DETAILS",
  "externalAccountDetails": {
    "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "currency": "BTC",
    "accountInfo": {
      "accountType": "SPARK_WALLET",
      "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu"
    }
  }
}

2. Quote Request - Source Discriminator Added

Before: Source was a oneOf without a discriminator
After: Added sourceType discriminator field

// Account source
{
  "sourceType": "ACCOUNT",
  "accountId": "InternalAccount:85dcbd6-dced-4ec4-b756-3c3a9ea3d965"
}

// Real-time funding source
{
  "sourceType": "REALTIME_FUNDING",
  "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000009",
  "currency": "USD"
}

3. Quote Response - Destination Discriminator Added

Before: Inline destination types
After: Extracted to QuoteAccountDestination and QuoteUmaAddressDestination with discriminator

// Quote response with account destination
{
  "id": "Quote:abc123",
  "destination": {
    "destinationType": "ACCOUNT",
    "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
    "currency": "EUR"
  }
}

// Quote response with UMA address destination
{
  "id": "Quote:abc123",
  "destination": {
    "destinationType": "UMA_ADDRESS",
    "umaAddress": "$receiver@uma.domain.com",
    "currency": "EUR",
    "counterpartyInformation": {
      "FULL_NAME": "Jane Receiver",
      "BIRTH_DATE": "1990-01-01",
      "NATIONALITY": "FR"
    }
  }
}

4. Transaction - Source/Destination Discriminators Added

Before: Inline source/destination types
After: Extracted with sourceType and destinationType discriminators

// Outgoing transaction with account source
{
  "id": "Transaction:xyz789",
  "type": "OUTGOING",
  "source": {
    "sourceType": "ACCOUNT",
    "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965",
    "currency": "USD"
  },
  "destination": {
    "destinationType": "UMA_ADDRESS",
    "umaAddress": "$receiver@uma.domain.com",
    "currency": "EUR"
  }
}

// Incoming transaction with UMA source
{
  "id": "Transaction:xyz789",
  "type": "INCOMING",
  "source": {
    "sourceType": "UMA_ADDRESS",
    "umaAddress": "$sender@uma.domain.com",
    "currency": "USD"
  },
  "destination": {
    "destinationType": "ACCOUNT",
    "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
    "currency": "EUR"
  }
}

5. Lightning External Account - Flattened Structure

Before: Nested oneOf with separate invoice/bolt12/lightningAddress objects
After: Flattened to single object with optional fields

// Before (one of these)
{
  "accountType": "LIGHTNING",
  "invoice": "lnbc15u1p3xnhl2pp5..."
}
// OR
{
  "accountType": "LIGHTNING",
  "bolt12": "lnbc15u1p3xnhl2pp5..."
}
// OR
{
  "accountType": "LIGHTNING",
  "lightningAddress": "john.doe@lightningwallet.com"
}

// After (single object, fields are optional)
{
  "accountType": "LIGHTNING",
  "invoice": "lnbc15u1p3xnhl2pp5...",
  "bolt12": "lnbc15u1p3xnhl2pp5...",
  "lightningAddress": "john.doe@lightningwallet.com"
}

6. Create Customer Request - Discriminator Added

Before: Inline oneOf with individual/business types
After: Extracted to CreateCustomerRequest with customerType discriminator

// Create individual customer
{
  "customerType": "INDIVIDUAL",
  "platformCustomerId": "9f84e0c2a72c4fa",
  "fullName": "Jane Doe",
  "birthDate": "1992-03-25",
  "address": {
    "line1": "123 Pine Street",
    "city": "Seattle",
    "state": "WA",
    "postalCode": "98101",
    "country": "US"
  }
}

// Create business customer
{
  "customerType": "BUSINESS",
  "platformCustomerId": "6e4d2c0b8a9f3",
  "umaAddress": "$acme@uma.domain.com",
  "address": {
    "line1": "400 Commerce Way",
    "city": "Austin",
    "state": "TX",
    "postalCode": "78701",
    "country": "US"
  }
}

7. Update Customer Request - Discriminator Added

Before: Inline oneOf
After: Extracted to UpdateCustomerRequest with customerType discriminator

// Update individual customer
{
  "customerType": "INDIVIDUAL",
  "fullName": "John Smith Updated",
  "birthDate": "1985-06-15"
}

// Update business customer  
{
  "customerType": "BUSINESS",
  "umaAddress": "$newaddress@uma.domain.com"
}

8. Customer Response - alias Field Removed

Before: Customer had an alias field
After: alias field removed from Customer schema

// Before
{
  "id": "Customer:abc123",
  "umaAddress": "$john.doe@uma.domain.com",
  "alias": "$alice-smith",
  "createdAt": "2025-01-23T10:00:00Z"
}

// After
{
  "id": "Customer:abc123",
  "umaAddress": "$john.doe@uma.domain.com",
  "createdAt": "2025-01-23T10:00:00Z"
}

9. Platform External Accounts - Response Field Renamed

Before: accounts array in response
After: data array in response

// Before
{
  "accounts": [
    { "id": "ExternalAccount:abc123", ... }
  ]
}

// After
{
  "data": [
    { "id": "ExternalAccount:abc123", ... }
  ]
}

10. Error Schema Renamed

Before: Error.yaml
After: GridError.yaml with additionalProperties: true on details

{
  "code": "INVALID_REQUEST",
  "message": "The request was invalid",
  "details": {
    "field": "email",
    "reason": "Invalid format"
  }
}

11. Single-Value Enums → const

All single-value enums converted to const for better SDK typing:

  • accountType: enum: [LIGHTNING]accountType: const: LIGHTNING
  • customerType: enum: [INDIVIDUAL]customerType: const: INDIVIDUAL
  • status: enum: [400]status: const: 400

This affects account types (IBAN, CLABE, FBO, PIX, NGN, etc.), customer types, and error status codes.


12. PaymentInstructions - New Field Added

After: Added isPlatformAccount boolean field

{
  "instructions": "Please include reference code in memo",
  "isPlatformAccount": true,
  "accountOrWalletInfo": {
    "accountType": "IBAN",
    "iban": "DE89370400440532013000",
    "swiftBic": "COBADEFFXXX"
  }
}

13. IndividualCustomerUpdate - platformCustomerId Added

After: Added platformCustomerId field to individual customer update schema

{
  "customerType": "INDIVIDUAL",
  "fullName": "Jane Doe",
  "platformCustomerId": "9f84e0c2a72c4fa"
}

@greptile-apps
Copy link

greptile-apps bot commented Jan 22, 2026

Greptile Summary

This PR refactors the OpenAPI specification to improve compatibility with Stainless SDK generation by adding discriminators to polymorphic types, converting single-value enums to const, and extracting inline schemas into reusable components.

Key Changes:

  • Added discriminators (sourceType, destinationType, customerType) to all oneOf schemas for proper SDK type generation
  • Converted enum: [SINGLE_VALUE] to const: SINGLE_VALUE throughout the spec (e.g., accountType, customerType)
  • Extracted inline request/response schemas into separate component files (Quote destinations/sources, Transaction sources/destinations, Customer requests)
  • Renamed Error schema to GridError to avoid naming conflicts
  • Added isPlatformAccount field to PaymentInstructions
  • Changed platform external accounts response field from accounts to data
  • Flattened Lightning external account structure from oneOf to optional fields
  • Added platformCustomerId to IndividualCustomerUpdate

Issues Found:

  • QuoteRealtimeFundingSource has customerId marked as required but description states it's optional for platform-level quotes (already flagged in previous thread)
  • Lightning external account flattening removes mutual exclusivity between invoice/bolt12/lightningAddress (already flagged in previous thread)

Confidence Score: 4/5

  • This PR is generally safe to merge with minor issues that should be addressed
  • The PR implements a systematic refactoring to improve SDK generation compatibility. The discriminator additions are well-structured and consistent. However, there are two known issues from previous review threads: (1) QuoteRealtimeFundingSource has a required/optional conflict for customerId, and (2) Lightning external account loses mutual exclusivity enforcement. These are design decisions that need clarification but don't introduce critical bugs.
  • Pay attention to openapi/components/schemas/quotes/QuoteRealtimeFundingSource.yaml and openapi/components/schemas/external_accounts/LightningExternalAccountInfo.yaml which have schema validation concerns already flagged in previous review threads

Important Files Changed

Filename Overview
openapi/components/schemas/quotes/QuoteRequest.yaml Added discriminators for source and destination oneOf schemas to improve SDK generation. Clean implementation with proper discriminator property names.
openapi/components/schemas/external_accounts/LightningExternalAccountInfo.yaml Changed from oneOf with mutual exclusivity to flattened structure with all three optional fields (invoice, bolt12, lightningAddress). This allows multiple destination types simultaneously, which may not be intended behavior.
openapi/components/schemas/customers/CreateCustomerRequest.yaml New extracted schema with customerType discriminator (enum INDIVIDUAL/BUSINESS) properly mapping to customer update schemas.
openapi/components/schemas/transactions/Transaction.yaml Added discriminators for destination oneOf (ACCOUNT/UMA_ADDRESS) and type discriminator for INCOMING/OUTGOING transaction subtypes.
openapi/components/schemas/quotes/QuoteRealtimeFundingSource.yaml New extracted schema for real-time funding source. customerId marked as required but description states it's optional for platform-level quotes - potential validation issue.
openapi/paths/platform/platform_external_accounts.yaml Renamed response field from accounts to data for consistency with API patterns. Clean breaking change.

Sequence Diagram

sequenceDiagram
    participant Client as SDK Client
    participant API as Grid API
    participant Quote as Quote Service
    participant Transaction as Transaction Service
    
    Note over Client,API: Quote Creation with Discriminators
    Client->>API: POST /quotes<br/>{source: {sourceType: "ACCOUNT", accountId: "..."}, <br/>destination: {destinationType: "UMA_ADDRESS", umaAddress: "$user@domain.com"}}
    API->>Quote: Validate discriminator fields
    Quote->>Quote: Route to appropriate handler<br/>based on sourceType & destinationType
    Quote-->>API: Quote created with discriminated types
    API-->>Client: Quote response<br/>{destination: {destinationType: "UMA_ADDRESS", ...}}
    
    Note over Client,API: Transaction Retrieval
    Client->>API: GET /transactions/{id}
    API->>Transaction: Fetch transaction
    Transaction-->>API: Transaction with discriminators<br/>{type: "OUTGOING", source: {sourceType: "ACCOUNT"}, <br/>destination: {destinationType: "UMA_ADDRESS"}}
    API-->>Client: SDK deserializes to correct type<br/>based on discriminators
    
    Note over Client,API: Customer Management
    Client->>API: POST /customers<br/>{customerType: "INDIVIDUAL", fullName: "...", ...}
    API->>API: Discriminator routes to<br/>IndividualCustomerUpdate schema
    API-->>Client: Customer created
    
    Client->>API: PUT /customers/{id}<br/>{customerType: "BUSINESS", businessInfo: {...}}
    API->>API: Discriminator routes to<br/>BusinessCustomerUpdate schema
    API-->>Client: Customer updated
Loading

Copy link

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

Additional Comments (1)

  1. openapi/components/schemas/common/PaymentLightningInvoiceInfo.yaml, line 2 (link)

    logic: This file still references ./PaymentAccountOrWalletInfo.yaml but all other Payment* schemas had this reference removed. This will cause schema resolution errors.

55 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link

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

Additional Comments (1)

  1. openapi/components/schemas/common/PaymentLightningInvoiceInfo.yaml, line 2 (link)

    logic: This reference to PaymentAccountOrWalletInfo.yaml must be removed. All other Payment* schemas in this PR had this reference removed, but this file was missed. This will cause schema resolution to fail.

69 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Copy link

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

Additional Comments (1)

  1. openapi/components/schemas/common/PaymentLightningInvoiceInfo.yaml, line 1-2 (link)

    logic: Circular dependency exists: PaymentLightningInvoiceInfo extends PaymentAccountOrWalletInfo, but PaymentAccountOrWalletInfo discriminator mapping references PaymentLightningInvoiceInfo. This creates an infinite loop that will prevent OpenAPI schema resolution and Stainless code generation from working.

    All other Payment* schemas (PaymentUsAccountInfo, PaymentClabeAccountInfo, etc.) extend their base schemas (UsAccountInfo, ClabeAccountInfo) which do NOT have this circular reference. Follow the same pattern here.

87 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link

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

Additional Comments (1)

  1. openapi/components/schemas/common/PaymentLightningInvoiceInfo.yaml, line 1-2 (link)

    logic: PaymentAccountOrWalletInfo reference should be removed for consistency with other Payment* schemas

    All other Payment* schemas (PaymentClabeAccountInfo, PaymentUsAccountInfo, PaymentPixAccountInfo, etc.) had their $ref: ./PaymentAccountOrWalletInfo.yaml removed in this PR. This file was missed.

    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!

89 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@pengying pengying force-pushed the peng-stainless_init branch from cc858e0 to 13ee030 Compare January 24, 2026 00:37
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