From b4720b996afff1d1212bb5d02174b83a9256db2f Mon Sep 17 00:00:00 2001 From: jaymantri Date: Wed, 18 Feb 2026 08:50:50 -0800 Subject: [PATCH 1/2] feat: add platform fee rules API endpoints and documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- mintlify/docs.json | 4 + .../global-p2p/platform-tools/fee-rules.mdx | 10 + mintlify/openapi.yaml | 1028 +++++++++++++---- .../platform-tools/fee-rules.mdx | 10 + mintlify/ramps/platform-tools/fee-rules.mdx | 10 + mintlify/rewards/platform-tools/fee-rules.mdx | 10 + mintlify/snippets/platform-fee-rules.mdx | 164 +++ openapi.yaml | 1028 +++++++++++++---- .../components/schemas/errors/Error400.yaml | 4 + .../components/schemas/errors/Error404.yaml | 2 + .../components/schemas/errors/Error409.yaml | 2 + .../schemas/fee_rules/FeeReport.yaml | 35 + .../schemas/fee_rules/FeeReportLine.yaml | 30 + .../components/schemas/fee_rules/FeeRule.yaml | 59 + .../fee_rules/FeeRuleCreateRequest.yaml | 34 + .../fee_rules/FeeRulePatchRequest.yaml | 27 + .../schemas/fee_rules/FeeRuleType.yaml | 10 + .../schemas/fee_rules/FeeTransactionType.yaml | 12 + .../transactions/IncomingRateDetails.yaml | 28 + .../transactions/OutgoingRateDetails.yaml | 28 + openapi/openapi.yaml | 11 + openapi/paths/fee-rules/fee_rules.yaml | 141 +++ openapi/paths/fee-rules/fee_rules_report.yaml | 70 ++ .../fee-rules/fee_rules_{feeRuleId}.yaml | 130 +++ 24 files changed, 2401 insertions(+), 486 deletions(-) create mode 100644 mintlify/global-p2p/platform-tools/fee-rules.mdx create mode 100644 mintlify/payouts-and-b2b/platform-tools/fee-rules.mdx create mode 100644 mintlify/ramps/platform-tools/fee-rules.mdx create mode 100644 mintlify/rewards/platform-tools/fee-rules.mdx create mode 100644 mintlify/snippets/platform-fee-rules.mdx create mode 100644 openapi/components/schemas/fee_rules/FeeReport.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeReportLine.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeRule.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeRuleCreateRequest.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeRulePatchRequest.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeRuleType.yaml create mode 100644 openapi/components/schemas/fee_rules/FeeTransactionType.yaml create mode 100644 openapi/paths/fee-rules/fee_rules.yaml create mode 100644 openapi/paths/fee-rules/fee_rules_report.yaml create mode 100644 openapi/paths/fee-rules/fee_rules_{feeRuleId}.yaml diff --git a/mintlify/docs.json b/mintlify/docs.json index b5ef95f7..d441c195 100644 --- a/mintlify/docs.json +++ b/mintlify/docs.json @@ -101,6 +101,7 @@ { "group": "Platform Tools", "pages": [ + "payouts-and-b2b/platform-tools/fee-rules", "payouts-and-b2b/platform-tools/webhooks", "payouts-and-b2b/platform-tools/sandbox-testing", "payouts-and-b2b/platform-tools/postman-collection" @@ -146,6 +147,7 @@ { "group": "Platform Tools", "pages": [ + "ramps/platform-tools/fee-rules", "ramps/platform-tools/webhooks", "ramps/platform-tools/sandbox-testing", "ramps/platform-tools/postman-collection" @@ -189,6 +191,7 @@ { "group": "Platform Tools", "pages": [ + "rewards/platform-tools/fee-rules", "rewards/platform-tools/webhooks", "rewards/platform-tools/sandbox-testing", "rewards/platform-tools/postman-collection" @@ -237,6 +240,7 @@ { "group": "Platform Tools", "pages": [ + "global-p2p/platform-tools/fee-rules", "global-p2p/platform-tools/webhooks", "global-p2p/platform-tools/sandbox-testing", "global-p2p/platform-tools/postman-collection", diff --git a/mintlify/global-p2p/platform-tools/fee-rules.mdx b/mintlify/global-p2p/platform-tools/fee-rules.mdx new file mode 100644 index 00000000..50d89345 --- /dev/null +++ b/mintlify/global-p2p/platform-tools/fee-rules.mdx @@ -0,0 +1,10 @@ +--- +title: "Platform fee rules" +description: "Configure the markup your platform charges customers per transaction type" +icon: "/images/icons/settings-gear2.svg" +"og:image": "/images/og/og-global-p2p.png" +--- + +import PlatformFeeRules from '/snippets/platform-fee-rules.mdx'; + + diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index ed3f2874..2753aba6 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -38,9 +38,333 @@ tags: description: Endpoints to trigger test cases in sandbox - name: API Tokens description: Endpoints to programmatically manage API tokens + - name: Platform Fee Rules + description: Configure the markup your platform charges customers on each transaction type. Platform fees are layered on top of Lightspark and counterparty fees and collected in real time during settlement. - name: Exchange Rates description: Endpoints for retrieving cached foreign exchange rates. Rates are cached for approximately 5 minutes and include platform-specific fees. paths: + /fee-rules: + post: + summary: Create a fee rule + description: | + Create a platform fee rule for a specific transaction type. The rule defines the markup your platform charges customers on top of Lightspark and counterparty fees. Only one rule per transaction type is allowed. + + Fee rules are evaluated at quote creation time. The resulting platform fee is included in the quote's `rateDetails` and collected in real time during settlement — no manual reconciliation is needed. + + **Fee types:** + - `FIXED` — a flat amount per transaction (requires `fixedFee`) + - `PERCENTAGE` — a rate of the transaction amount (requires `variableFeeRate`) + - `HYBRID` — both a fixed amount and a percentage rate (requires both) + operationId: createFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRuleCreateRequest' + examples: + fixedFee: + summary: Fixed fee of $1.50 on transfers out + value: + transactionType: TRANSFER_OUT + feeType: FIXED + fixedFee: 150 + percentageFee: + summary: 0.5% fee on cross-border payouts + value: + transactionType: CROSS_BORDER_PAYOUT + feeType: PERCENTAGE + variableFeeRate: 0.005 + hybridFee: + summary: $1.50 + 0.5% on off-ramps + value: + transactionType: RAMP_OFF + feeType: HYBRID + fixedFee: 150 + variableFeeRate: 0.005 + responses: + '201': + description: Fee rule created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '400': + description: Invalid input — missing required fields, invalid feeType, or fee amounts out of range + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '409': + description: A fee rule for this transaction type already exists + content: + application/json: + schema: + $ref: '#/components/schemas/Error409' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + get: + summary: List fee rules + description: | + Retrieve all platform fee rules. Returns the complete set of configured rules. Since the maximum number of rules is bounded by the number of transaction types (5), pagination is not required. + operationId: listFeeRules + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: transactionType + in: query + description: Filter by transaction type + required: false + schema: + $ref: '#/components/schemas/FeeTransactionType' + - name: enabled + in: query + description: Filter by enabled status + required: false + schema: + type: boolean + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + description: List of platform fee rules + items: + $ref: '#/components/schemas/FeeRule' + '400': + description: Bad request — invalid query parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + /fee-rules/{feeRuleId}: + parameters: + - name: feeRuleId + in: path + description: System-generated unique fee rule identifier + required: true + schema: + type: string + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 + get: + summary: Get fee rule by ID + description: Retrieve a single platform fee rule by its system-generated ID. + operationId: getFeeRuleById + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + patch: + summary: Update a fee rule + description: | + Partially update an existing fee rule. Only the provided fields are modified. The `transactionType` and `feeType` cannot be changed — delete and recreate the rule instead. + operationId: updateFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRulePatchRequest' + examples: + disableRule: + summary: Disable a fee rule + value: + enabled: false + updateFee: + summary: Update fixed fee amount + value: + fixedFee: 200 + responses: + '200': + description: Fee rule updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '400': + description: Invalid input — fee amounts out of range + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + delete: + summary: Delete a fee rule + description: | + Delete a platform fee rule. Future transactions of this type will no longer include a platform markup. Transactions already in progress or settled are unaffected. + operationId: deleteFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '204': + description: Fee rule deleted successfully + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + /fee-rules/report: + get: + summary: Get monthly fee report + description: | + Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. + + The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. + operationId: getFeeReport + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: month + in: query + description: Reporting month in YYYY-MM format. Defaults to the current month. + required: false + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeReport' + examples: + monthlyReport: + summary: February 2026 fee report + value: + month: 2026-02 + totalPlatformFeesCollected: 128450 + currency: USD + lines: + - transactionType: TRANSFER_OUT + transactionCount: 245 + platformFeesCollected: 62500 + currency: USD + - transactionType: CROSS_BORDER_PAYOUT + transactionCount: 97 + platformFeesCollected: 51300 + currency: USD + - transactionType: RAMP_OFF + transactionCount: 58 + platformFeesCollected: 14650 + currency: USD + '400': + description: Invalid month format + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /config: get: summary: Get platform configuration @@ -3924,46 +4248,435 @@ components: - $ref: '#/components/schemas/Error424' - $ref: '#/components/schemas/Error500' - $ref: '#/components/schemas/Error501' - CustomerInfoFieldName: + FeeTransactionType: type: string + description: The type of transaction the fee rule applies to. Platform fee rules are scoped to a single transaction type — only one rule per type is allowed. enum: - - FULL_NAME - - BIRTH_DATE - - NATIONALITY - - PHONE_NUMBER - - EMAIL - - POSTAL_ADDRESS - - TAX_ID - - REGISTRATION_NUMBER - - USER_TYPE - - COUNTRY_OF_RESIDENCE - - ACCOUNT_IDENTIFIER - - FI_LEGAL_ENTITY_NAME - - FI_ADDRESS - - PURPOSE_OF_PAYMENT - - ULTIMATE_INSTITUTION_COUNTRY - - IDENTIFIER - description: Name of a type of field containing info about a platform's customer or counterparty customer. - example: FULL_NAME - CounterpartyFieldDefinition: - type: object - properties: - name: - $ref: '#/components/schemas/CustomerInfoFieldName' - mandatory: - type: boolean - description: Whether the field is mandatory - example: true - required: - - name - - mandatory - TransactionType: + - TRANSFER_IN + - TRANSFER_OUT + - RAMP_ON + - RAMP_OFF + - CROSS_BORDER_PAYOUT + example: CROSS_BORDER_PAYOUT + FeeRuleType: type: string + description: Determines which fee components apply. FIXED charges a flat amount per transaction. PERCENTAGE charges a rate of the transaction amount. HYBRID applies both a fixed amount and a percentage rate. enum: - - INCOMING - - OUTGOING - description: Type of transaction (incoming payment or outgoing payment) - PlatformCurrencyConfig: + - FIXED + - PERCENTAGE + - HYBRID + example: HYBRID + FeeRule: + type: object + description: A platform fee rule defines the markup a platform charges its customers on a specific transaction type, on top of Lightspark and counterparty fees. Rules are evaluated at quote creation and the resulting platform fee is collected in real time during settlement. + required: + - id + - transactionType + - feeType + - enabled + - createdAt + - updatedAt + properties: + id: + type: string + description: System-generated unique identifier + readOnly: true + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + feeType: + $ref: '#/components/schemas/FeeRuleType' + 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 + example: 150 + variableFeeRate: + type: number + format: double + 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. + minimum: 0 + maximum: 0.2 + example: 0.005 + enabled: + type: boolean + description: Whether this fee rule is actively applied to new transactions. Disabled rules are retained for reporting but do not affect new quotes. + example: true + createdAt: + type: string + format: date-time + description: When the fee rule was created + readOnly: true + example: '2026-01-15T00:00:00Z' + updatedAt: + type: string + format: date-time + description: When the fee rule was last modified + readOnly: true + example: '2026-02-01T12:30:00Z' + Error400: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 400 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | INVALID_INPUT | Invalid input provided | + | MISSING_MANDATORY_USER_INFO | Required customer information is missing | + | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed | + | INVITATIONS_NOT_CONFIGURED | Invitations are not configured | + | INVALID_UMA_ADDRESS | UMA address format is invalid | + | INVITATION_CANCELLED | Invitation has been cancelled | + | QUOTE_REQUEST_FAILED | An issue occurred during the quote process; this is retryable | + | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid | + | INVALID_RECEIVER | Receiver is invalid | + | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response | + | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid | + | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired | + | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid | + | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing | + | SENDER_NOT_ACCEPTED | Sender is not accepted | + | AMOUNT_OUT_OF_RANGE | Amount is out of range | + | INVALID_CURRENCY | Currency is invalid | + | INVALID_TIMESTAMP | Timestamp is invalid | + | INVALID_NONCE | Nonce is invalid | + | INVALID_REQUEST_FORMAT | Request format is invalid | + | INVALID_BANK_ACCOUNT | Bank account is invalid | + | SELF_PAYMENT | Self payment not allowed | + | LOOKUP_REQUEST_FAILED | Lookup request failed | + | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response | + | INVALID_AMOUNT | Amount is invalid | + | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | + | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | + | INVALID_FEE_RULE | Fee rule input is invalid (missing fields, amounts out of range, or wrong feeType/field combination) | + | INVALID_MONTH_FORMAT | Month parameter must be in YYYY-MM format | + enum: + - INVALID_INPUT + - MISSING_MANDATORY_USER_INFO + - INVITATION_ALREADY_CLAIMED + - INVITATIONS_NOT_CONFIGURED + - INVALID_UMA_ADDRESS + - INVITATION_CANCELLED + - QUOTE_REQUEST_FAILED + - INVALID_PAYREQ_RESPONSE + - INVALID_RECEIVER + - PARSE_PAYREQ_RESPONSE_ERROR + - CERT_CHAIN_INVALID + - CERT_CHAIN_EXPIRED + - INVALID_PUBKEY_FORMAT + - MISSING_REQUIRED_UMA_PARAMETERS + - SENDER_NOT_ACCEPTED + - AMOUNT_OUT_OF_RANGE + - INVALID_CURRENCY + - INVALID_TIMESTAMP + - INVALID_NONCE + - INVALID_REQUEST_FORMAT + - INVALID_BANK_ACCOUNT + - SELF_PAYMENT + - LOOKUP_REQUEST_FAILED + - PARSE_LNURLP_RESPONSE_ERROR + - INVALID_AMOUNT + - WEBHOOK_ENDPOINT_NOT_SET + - WEBHOOK_DELIVERY_ERROR + - INVALID_FEE_RULE + - INVALID_MONTH_FORMAT + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error401: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 401 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | UNAUTHORIZED | Issue with API credentials | + | INVALID_SIGNATURE | Signature header is invalid | + enum: + - UNAUTHORIZED + - INVALID_SIGNATURE + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error500: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 500 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | GRID_SWITCH_ERROR | Grid switch error | + | INTERNAL_ERROR | Internal server or UMA error | + enum: + - GRID_SWITCH_ERROR + - INTERNAL_ERROR + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + FeeRuleCreateRequest: + type: object + description: Request body for creating a new platform fee rule. + required: + - transactionType + - feeType + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + feeType: + $ref: '#/components/schemas/FeeRuleType' + fixedFee: + type: integer + format: int64 + description: Fixed fee in the smallest unit of USD (cents). Required when feeType is FIXED or HYBRID. Must be between 0 and 10000 ($100.00). + minimum: 0 + maximum: 10000 + example: 150 + variableFeeRate: + type: number + format: double + description: Variable fee as a decimal rate (e.g., 0.005 = 0.5%). Required when feeType is PERCENTAGE or HYBRID. Must be between 0 and 0.20 (20%). + minimum: 0 + maximum: 0.2 + example: 0.005 + enabled: + type: boolean + description: Whether the rule should be active immediately. Defaults to true. + default: true + example: true + Error409: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 409 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL | Transaction is not pending platform approval | + | UMA_ADDRESS_EXISTS | UMA address already exists | + | FEE_RULE_EXISTS | A fee rule for this transaction type already exists | + enum: + - TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL + - UMA_ADDRESS_EXISTS + - FEE_RULE_EXISTS + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error404: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 404 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | TRANSACTION_NOT_FOUND | Transaction not found | + | INVITATION_NOT_FOUND | Invitation not found | + | USER_NOT_FOUND | Customer not found | + | QUOTE_NOT_FOUND | Quote not found | + | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found | + | TOKEN_NOT_FOUND | Token not found | + | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | + | REFERENCE_NOT_FOUND | Reference not found | + | FEE_RULE_NOT_FOUND | Fee rule not found | + enum: + - TRANSACTION_NOT_FOUND + - INVITATION_NOT_FOUND + - USER_NOT_FOUND + - QUOTE_NOT_FOUND + - LOOKUP_REQUEST_NOT_FOUND + - TOKEN_NOT_FOUND + - BULK_UPLOAD_JOB_NOT_FOUND + - REFERENCE_NOT_FOUND + - FEE_RULE_NOT_FOUND + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + FeeRulePatchRequest: + type: object + description: Partial update for an existing fee rule. Only provided fields are updated. The transactionType and feeType cannot be changed — delete and recreate the rule instead. + properties: + fixedFee: + type: integer + format: int64 + description: Updated fixed fee in the smallest unit of USD (cents). Must be between 0 and 10000. + minimum: 0 + maximum: 10000 + example: 200 + variableFeeRate: + type: number + format: double + description: Updated variable fee as a decimal rate. Must be between 0 and 0.20. + minimum: 0 + maximum: 0.2 + example: 0.01 + enabled: + type: boolean + description: Enable or disable the fee rule + example: false + FeeReportLine: + type: object + description: Aggregated platform fee revenue for a single transaction type within a reporting period. + required: + - transactionType + - transactionCount + - platformFeesCollected + - currency + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + transactionCount: + type: integer + description: Number of settled transactions that incurred this fee + minimum: 0 + example: 342 + platformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 51300 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + FeeReport: + type: object + description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. + required: + - month + - totalPlatformFeesCollected + - currency + - lines + properties: + month: + type: string + description: Reporting month in YYYY-MM format. + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + totalPlatformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 128450 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + lines: + type: array + description: Per-transaction-type breakdown of collected fees + items: + $ref: '#/components/schemas/FeeReportLine' + CustomerInfoFieldName: + type: string + enum: + - FULL_NAME + - BIRTH_DATE + - NATIONALITY + - PHONE_NUMBER + - EMAIL + - POSTAL_ADDRESS + - TAX_ID + - REGISTRATION_NUMBER + - USER_TYPE + - COUNTRY_OF_RESIDENCE + - ACCOUNT_IDENTIFIER + - FI_LEGAL_ENTITY_NAME + - FI_ADDRESS + - PURPOSE_OF_PAYMENT + - ULTIMATE_INSTITUTION_COUNTRY + - IDENTIFIER + description: Name of a type of field containing info about a platform's customer or counterparty customer. + example: FULL_NAME + CounterpartyFieldDefinition: + type: object + properties: + name: + $ref: '#/components/schemas/CustomerInfoFieldName' + mandatory: + type: boolean + description: Whether the field is mandatory + example: true + required: + - name + - mandatory + TransactionType: + type: string + enum: + - INCOMING + - OUTGOING + description: Type of transaction (incoming payment or outgoing payment) + PlatformCurrencyConfig: type: object properties: currencyCode: @@ -4073,143 +4786,6 @@ components: description: Last update timestamp readOnly: true example: '2025-06-15T12:30:45Z' - Error401: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 401 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | UNAUTHORIZED | Issue with API credentials | - | INVALID_SIGNATURE | Signature header is invalid | - enum: - - UNAUTHORIZED - - INVALID_SIGNATURE - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error500: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 500 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | GRID_SWITCH_ERROR | Grid switch error | - | INTERNAL_ERROR | Internal server or UMA error | - enum: - - GRID_SWITCH_ERROR - - INTERNAL_ERROR - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error400: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 400 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | INVALID_INPUT | Invalid input provided | - | MISSING_MANDATORY_USER_INFO | Required customer information is missing | - | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed | - | INVITATIONS_NOT_CONFIGURED | Invitations are not configured | - | INVALID_UMA_ADDRESS | UMA address format is invalid | - | INVITATION_CANCELLED | Invitation has been cancelled | - | QUOTE_REQUEST_FAILED | An issue occurred during the quote process; this is retryable | - | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid | - | INVALID_RECEIVER | Receiver is invalid | - | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response | - | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid | - | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired | - | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid | - | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing | - | SENDER_NOT_ACCEPTED | Sender is not accepted | - | AMOUNT_OUT_OF_RANGE | Amount is out of range | - | INVALID_CURRENCY | Currency is invalid | - | INVALID_TIMESTAMP | Timestamp is invalid | - | INVALID_NONCE | Nonce is invalid | - | INVALID_REQUEST_FORMAT | Request format is invalid | - | INVALID_BANK_ACCOUNT | Bank account is invalid | - | SELF_PAYMENT | Self payment not allowed | - | LOOKUP_REQUEST_FAILED | Lookup request failed | - | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response | - | INVALID_AMOUNT | Amount is invalid | - | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | - | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | - enum: - - INVALID_INPUT - - MISSING_MANDATORY_USER_INFO - - INVITATION_ALREADY_CLAIMED - - INVITATIONS_NOT_CONFIGURED - - INVALID_UMA_ADDRESS - - INVITATION_CANCELLED - - QUOTE_REQUEST_FAILED - - INVALID_PAYREQ_RESPONSE - - INVALID_RECEIVER - - PARSE_PAYREQ_RESPONSE_ERROR - - CERT_CHAIN_INVALID - - CERT_CHAIN_EXPIRED - - INVALID_PUBKEY_FORMAT - - MISSING_REQUIRED_UMA_PARAMETERS - - SENDER_NOT_ACCEPTED - - AMOUNT_OUT_OF_RANGE - - INVALID_CURRENCY - - INVALID_TIMESTAMP - - INVALID_NONCE - - INVALID_REQUEST_FORMAT - - INVALID_BANK_ACCOUNT - - SELF_PAYMENT - - LOOKUP_REQUEST_FAILED - - PARSE_LNURLP_RESPONSE_ERROR - - INVALID_AMOUNT - - WEBHOOK_ENDPOINT_NOT_SET - - WEBHOOK_DELIVERY_ERROR - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true Error501: type: object required: @@ -4620,76 +5196,6 @@ components: mapping: INDIVIDUAL: '#/components/schemas/IndividualCustomerCreateRequest' BUSINESS: '#/components/schemas/BusinessCustomerCreateRequest' - Error409: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 409 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL | Transaction is not pending platform approval | - | UMA_ADDRESS_EXISTS | UMA address already exists | - enum: - - TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL - - UMA_ADDRESS_EXISTS - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error404: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 404 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | TRANSACTION_NOT_FOUND | Transaction not found | - | INVITATION_NOT_FOUND | Invitation not found | - | USER_NOT_FOUND | Customer not found | - | QUOTE_NOT_FOUND | Quote not found | - | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found | - | TOKEN_NOT_FOUND | Token not found | - | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | - | REFERENCE_NOT_FOUND | Reference not found | - enum: - - TRANSACTION_NOT_FOUND - - INVITATION_NOT_FOUND - - USER_NOT_FOUND - - QUOTE_NOT_FOUND - - LOOKUP_REQUEST_NOT_FOUND - - TOKEN_NOT_FOUND - - BULK_UPLOAD_JOB_NOT_FOUND - - REFERENCE_NOT_FOUND - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true Error410: type: object required: @@ -6003,6 +6509,24 @@ components: description: The variable fee amount charged by the Grid product to execute the quote in the smallest unit of the receiving currency (eg. cents). This is the receiving amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: The fixed fee configured by the platform for this transaction type, in the smallest unit of USD (cents). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: The variable fee rate configured by the platform as a decimal (e.g., 0.005 = 0.5%). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: The calculated variable fee amount from the platform's fee rule, in the smallest unit of the receiving currency (eg. cents). This is the receiving amount times platformVariableFeeRate. Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 50 IncomingTransactionFailureReason: type: string enum: @@ -6103,6 +6627,24 @@ components: description: The variable fee amount charged by the Grid product to execute the quote in the smallest unit of the sending currency (eg. cents). This is the sending amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: The fixed fee configured by the platform for this transaction type, in the smallest unit of USD (cents). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: The variable fee rate configured by the platform as a decimal (e.g., 0.005 = 0.5%). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: The calculated variable fee amount from the platform's fee rule, in the smallest unit of the sending currency (eg. cents). This is the sending amount times platformVariableFeeRate. Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 50 OutgoingTransactionFailureReason: type: string enum: diff --git a/mintlify/payouts-and-b2b/platform-tools/fee-rules.mdx b/mintlify/payouts-and-b2b/platform-tools/fee-rules.mdx new file mode 100644 index 00000000..3c499767 --- /dev/null +++ b/mintlify/payouts-and-b2b/platform-tools/fee-rules.mdx @@ -0,0 +1,10 @@ +--- +title: "Platform fee rules" +description: "Configure the markup your platform charges customers per transaction type" +icon: "/images/icons/settings-gear2.svg" +"og:image": "/images/og/og-payouts-b2b.png" +--- + +import PlatformFeeRules from '/snippets/platform-fee-rules.mdx'; + + diff --git a/mintlify/ramps/platform-tools/fee-rules.mdx b/mintlify/ramps/platform-tools/fee-rules.mdx new file mode 100644 index 00000000..10a50a54 --- /dev/null +++ b/mintlify/ramps/platform-tools/fee-rules.mdx @@ -0,0 +1,10 @@ +--- +title: "Platform fee rules" +description: "Configure the markup your platform charges customers per transaction type" +icon: "/images/icons/settings-gear2.svg" +"og:image": "/images/og/og-ramps.png" +--- + +import PlatformFeeRules from '/snippets/platform-fee-rules.mdx'; + + diff --git a/mintlify/rewards/platform-tools/fee-rules.mdx b/mintlify/rewards/platform-tools/fee-rules.mdx new file mode 100644 index 00000000..831cae98 --- /dev/null +++ b/mintlify/rewards/platform-tools/fee-rules.mdx @@ -0,0 +1,10 @@ +--- +title: "Platform fee rules" +description: "Configure the markup your platform charges customers per transaction type" +icon: "/images/icons/settings-gear2.svg" +"og:image": "/images/og/og-rewards.png" +--- + +import PlatformFeeRules from '/snippets/platform-fee-rules.mdx'; + + diff --git a/mintlify/snippets/platform-fee-rules.mdx b/mintlify/snippets/platform-fee-rules.mdx new file mode 100644 index 00000000..916cf84d --- /dev/null +++ b/mintlify/snippets/platform-fee-rules.mdx @@ -0,0 +1,164 @@ +import { gridBaseUrl } from '/snippets/variables.mdx'; + +Platform fee rules let you define the markup your platform charges customers on +each transaction type. Fees are layered on top of Lightspark and counterparty +fees, and collected in real time during settlement. + +## How platform fees work + +When a customer initiates a transaction, Grid evaluates your fee rules and +includes the platform markup in the quote. At settlement, the platform fee is +siphoned from the transaction amount and credited to your platform subledger. + +The total fee a customer sees is the sum of three layers: + +| Layer | Source | Configurable? | +|-------|--------|---------------| +| Network/rail fees | Counterparty institution | No | +| Lightspark fees | Grid API | No | +| Platform markup | Your fee rules | Yes | + +Platform fee fields appear alongside existing fee fields in quote and +transaction `rateDetails`: + +- `platformFixedFee` — your fixed fee in USD cents +- `platformVariableFeeRate` — your variable rate as a decimal (e.g., 0.005 = 0.5%) +- `platformVariableFeeAmount` — the calculated variable fee amount + +## Supported transaction types + +You can configure one fee rule per transaction type: + +| Transaction type | Description | +|------------------|-------------| +| `TRANSFER_IN` | Fiat or crypto transfer in (same currency) | +| `TRANSFER_OUT` | Fiat or crypto transfer out (same currency) | +| `RAMP_ON` | Fiat-to-crypto conversion | +| `RAMP_OFF` | Crypto-to-fiat conversion | +| `CROSS_BORDER_PAYOUT` | Cross-border payment via UMA or external account | + +## Fee types + +Each rule uses one of three fee types: + +| Fee type | Fields required | Example | +|----------|----------------|---------| +| `FIXED` | `fixedFee` | $1.50 flat per transaction | +| `PERCENTAGE` | `variableFeeRate` | 0.5% of transaction amount | +| `HYBRID` | `fixedFee` + `variableFeeRate` | $1.50 + 0.5% | + +## Create a fee rule + + + + +Decide which transaction type to charge and whether to use a fixed fee, +percentage, or both. + + + + + +```bash cURL +curl -X POST https://api.lightspark.com/grid/2025-10-13/fee-rules \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ + "transactionType": "CROSS_BORDER_PAYOUT", + "feeType": "HYBRID", + "fixedFee": 150, + "variableFeeRate": 0.005 + }' +``` + + +```json 201 Created +{ + "id": "FeeRule:019c6a2b-4f8e-7d01-0000-000000000001", + "transactionType": "CROSS_BORDER_PAYOUT", + "feeType": "HYBRID", + "fixedFee": 150, + "variableFeeRate": 0.005, + "enabled": true, + "createdAt": "2026-02-15T00:00:00Z", + "updatedAt": "2026-02-15T00:00:00Z" +} +``` + + + +The rule is active immediately. New quotes for cross-border payouts will include +your platform markup in `rateDetails`. + + + + + +## Update a fee rule + +Use `PATCH` to update the fee amounts or enable/disable a rule. You cannot +change the `transactionType` or `feeType` — delete and recreate the rule +instead. + +```bash cURL +curl -X PATCH https://api.lightspark.com/grid/2025-10-13/fee-rules/FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{"fixedFee": 200}' +``` + +To temporarily disable a rule without deleting it: + +```bash cURL +curl -X PATCH https://api.lightspark.com/grid/2025-10-13/fee-rules/FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{"enabled": false}' +``` + +## View fee revenue + +Retrieve a monthly summary of collected platform fees, broken down by +transaction type: + +```bash cURL +curl https://api.lightspark.com/grid/2025-10-13/fee-rules/report?month=2026-02 \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" +``` + + +```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" + } + ] +} +``` + + +## Constraints + +- One rule per transaction type (attempting to create a duplicate returns `409`) +- Fixed fees: 0–10,000 cents ($0–$100.00) +- Variable rates: 0–0.20 (0%–20%) +- Fee collection currency is always USD +- Disabled rules are retained for reporting but do not affect new quotes + + +Changes to fee rules take effect on new quotes only. Transactions already in +progress or settled are unaffected. + diff --git a/openapi.yaml b/openapi.yaml index ed3f2874..2753aba6 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -38,9 +38,333 @@ tags: description: Endpoints to trigger test cases in sandbox - name: API Tokens description: Endpoints to programmatically manage API tokens + - name: Platform Fee Rules + description: Configure the markup your platform charges customers on each transaction type. Platform fees are layered on top of Lightspark and counterparty fees and collected in real time during settlement. - name: Exchange Rates description: Endpoints for retrieving cached foreign exchange rates. Rates are cached for approximately 5 minutes and include platform-specific fees. paths: + /fee-rules: + post: + summary: Create a fee rule + description: | + Create a platform fee rule for a specific transaction type. The rule defines the markup your platform charges customers on top of Lightspark and counterparty fees. Only one rule per transaction type is allowed. + + Fee rules are evaluated at quote creation time. The resulting platform fee is included in the quote's `rateDetails` and collected in real time during settlement — no manual reconciliation is needed. + + **Fee types:** + - `FIXED` — a flat amount per transaction (requires `fixedFee`) + - `PERCENTAGE` — a rate of the transaction amount (requires `variableFeeRate`) + - `HYBRID` — both a fixed amount and a percentage rate (requires both) + operationId: createFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRuleCreateRequest' + examples: + fixedFee: + summary: Fixed fee of $1.50 on transfers out + value: + transactionType: TRANSFER_OUT + feeType: FIXED + fixedFee: 150 + percentageFee: + summary: 0.5% fee on cross-border payouts + value: + transactionType: CROSS_BORDER_PAYOUT + feeType: PERCENTAGE + variableFeeRate: 0.005 + hybridFee: + summary: $1.50 + 0.5% on off-ramps + value: + transactionType: RAMP_OFF + feeType: HYBRID + fixedFee: 150 + variableFeeRate: 0.005 + responses: + '201': + description: Fee rule created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '400': + description: Invalid input — missing required fields, invalid feeType, or fee amounts out of range + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '409': + description: A fee rule for this transaction type already exists + content: + application/json: + schema: + $ref: '#/components/schemas/Error409' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + get: + summary: List fee rules + description: | + Retrieve all platform fee rules. Returns the complete set of configured rules. Since the maximum number of rules is bounded by the number of transaction types (5), pagination is not required. + operationId: listFeeRules + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: transactionType + in: query + description: Filter by transaction type + required: false + schema: + $ref: '#/components/schemas/FeeTransactionType' + - name: enabled + in: query + description: Filter by enabled status + required: false + schema: + type: boolean + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + description: List of platform fee rules + items: + $ref: '#/components/schemas/FeeRule' + '400': + description: Bad request — invalid query parameters + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + /fee-rules/{feeRuleId}: + parameters: + - name: feeRuleId + in: path + description: System-generated unique fee rule identifier + required: true + schema: + type: string + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 + get: + summary: Get fee rule by ID + description: Retrieve a single platform fee rule by its system-generated ID. + operationId: getFeeRuleById + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + patch: + summary: Update a fee rule + description: | + Partially update an existing fee rule. Only the provided fields are modified. The `transactionType` and `feeType` cannot be changed — delete and recreate the rule instead. + operationId: updateFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRulePatchRequest' + examples: + disableRule: + summary: Disable a fee rule + value: + enabled: false + updateFee: + summary: Update fixed fee amount + value: + fixedFee: 200 + responses: + '200': + description: Fee rule updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/FeeRule' + '400': + description: Invalid input — fee amounts out of range + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + delete: + summary: Delete a fee rule + description: | + Delete a platform fee rule. Future transactions of this type will no longer include a platform markup. Transactions already in progress or settled are unaffected. + operationId: deleteFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '204': + description: Fee rule deleted successfully + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error404' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' + /fee-rules/report: + get: + summary: Get monthly fee report + description: | + Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. + + The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. + operationId: getFeeReport + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: month + in: query + description: Reporting month in YYYY-MM format. Defaults to the current month. + required: false + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeReport' + examples: + monthlyReport: + summary: February 2026 fee report + value: + month: 2026-02 + totalPlatformFeesCollected: 128450 + currency: USD + lines: + - transactionType: TRANSFER_OUT + transactionCount: 245 + platformFeesCollected: 62500 + currency: USD + - transactionType: CROSS_BORDER_PAYOUT + transactionCount: 97 + platformFeesCollected: 51300 + currency: USD + - transactionType: RAMP_OFF + transactionCount: 58 + platformFeesCollected: 14650 + currency: USD + '400': + description: Invalid month format + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /config: get: summary: Get platform configuration @@ -3924,46 +4248,435 @@ components: - $ref: '#/components/schemas/Error424' - $ref: '#/components/schemas/Error500' - $ref: '#/components/schemas/Error501' - CustomerInfoFieldName: + FeeTransactionType: type: string + description: The type of transaction the fee rule applies to. Platform fee rules are scoped to a single transaction type — only one rule per type is allowed. enum: - - FULL_NAME - - BIRTH_DATE - - NATIONALITY - - PHONE_NUMBER - - EMAIL - - POSTAL_ADDRESS - - TAX_ID - - REGISTRATION_NUMBER - - USER_TYPE - - COUNTRY_OF_RESIDENCE - - ACCOUNT_IDENTIFIER - - FI_LEGAL_ENTITY_NAME - - FI_ADDRESS - - PURPOSE_OF_PAYMENT - - ULTIMATE_INSTITUTION_COUNTRY - - IDENTIFIER - description: Name of a type of field containing info about a platform's customer or counterparty customer. - example: FULL_NAME - CounterpartyFieldDefinition: - type: object - properties: - name: - $ref: '#/components/schemas/CustomerInfoFieldName' - mandatory: - type: boolean - description: Whether the field is mandatory - example: true - required: - - name - - mandatory - TransactionType: + - TRANSFER_IN + - TRANSFER_OUT + - RAMP_ON + - RAMP_OFF + - CROSS_BORDER_PAYOUT + example: CROSS_BORDER_PAYOUT + FeeRuleType: type: string + description: Determines which fee components apply. FIXED charges a flat amount per transaction. PERCENTAGE charges a rate of the transaction amount. HYBRID applies both a fixed amount and a percentage rate. enum: - - INCOMING - - OUTGOING - description: Type of transaction (incoming payment or outgoing payment) - PlatformCurrencyConfig: + - FIXED + - PERCENTAGE + - HYBRID + example: HYBRID + FeeRule: + type: object + description: A platform fee rule defines the markup a platform charges its customers on a specific transaction type, on top of Lightspark and counterparty fees. Rules are evaluated at quote creation and the resulting platform fee is collected in real time during settlement. + required: + - id + - transactionType + - feeType + - enabled + - createdAt + - updatedAt + properties: + id: + type: string + description: System-generated unique identifier + readOnly: true + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + feeType: + $ref: '#/components/schemas/FeeRuleType' + 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 + example: 150 + variableFeeRate: + type: number + format: double + 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. + minimum: 0 + maximum: 0.2 + example: 0.005 + enabled: + type: boolean + description: Whether this fee rule is actively applied to new transactions. Disabled rules are retained for reporting but do not affect new quotes. + example: true + createdAt: + type: string + format: date-time + description: When the fee rule was created + readOnly: true + example: '2026-01-15T00:00:00Z' + updatedAt: + type: string + format: date-time + description: When the fee rule was last modified + readOnly: true + example: '2026-02-01T12:30:00Z' + Error400: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 400 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | INVALID_INPUT | Invalid input provided | + | MISSING_MANDATORY_USER_INFO | Required customer information is missing | + | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed | + | INVITATIONS_NOT_CONFIGURED | Invitations are not configured | + | INVALID_UMA_ADDRESS | UMA address format is invalid | + | INVITATION_CANCELLED | Invitation has been cancelled | + | QUOTE_REQUEST_FAILED | An issue occurred during the quote process; this is retryable | + | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid | + | INVALID_RECEIVER | Receiver is invalid | + | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response | + | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid | + | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired | + | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid | + | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing | + | SENDER_NOT_ACCEPTED | Sender is not accepted | + | AMOUNT_OUT_OF_RANGE | Amount is out of range | + | INVALID_CURRENCY | Currency is invalid | + | INVALID_TIMESTAMP | Timestamp is invalid | + | INVALID_NONCE | Nonce is invalid | + | INVALID_REQUEST_FORMAT | Request format is invalid | + | INVALID_BANK_ACCOUNT | Bank account is invalid | + | SELF_PAYMENT | Self payment not allowed | + | LOOKUP_REQUEST_FAILED | Lookup request failed | + | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response | + | INVALID_AMOUNT | Amount is invalid | + | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | + | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | + | INVALID_FEE_RULE | Fee rule input is invalid (missing fields, amounts out of range, or wrong feeType/field combination) | + | INVALID_MONTH_FORMAT | Month parameter must be in YYYY-MM format | + enum: + - INVALID_INPUT + - MISSING_MANDATORY_USER_INFO + - INVITATION_ALREADY_CLAIMED + - INVITATIONS_NOT_CONFIGURED + - INVALID_UMA_ADDRESS + - INVITATION_CANCELLED + - QUOTE_REQUEST_FAILED + - INVALID_PAYREQ_RESPONSE + - INVALID_RECEIVER + - PARSE_PAYREQ_RESPONSE_ERROR + - CERT_CHAIN_INVALID + - CERT_CHAIN_EXPIRED + - INVALID_PUBKEY_FORMAT + - MISSING_REQUIRED_UMA_PARAMETERS + - SENDER_NOT_ACCEPTED + - AMOUNT_OUT_OF_RANGE + - INVALID_CURRENCY + - INVALID_TIMESTAMP + - INVALID_NONCE + - INVALID_REQUEST_FORMAT + - INVALID_BANK_ACCOUNT + - SELF_PAYMENT + - LOOKUP_REQUEST_FAILED + - PARSE_LNURLP_RESPONSE_ERROR + - INVALID_AMOUNT + - WEBHOOK_ENDPOINT_NOT_SET + - WEBHOOK_DELIVERY_ERROR + - INVALID_FEE_RULE + - INVALID_MONTH_FORMAT + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error401: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 401 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | UNAUTHORIZED | Issue with API credentials | + | INVALID_SIGNATURE | Signature header is invalid | + enum: + - UNAUTHORIZED + - INVALID_SIGNATURE + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error500: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 500 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | GRID_SWITCH_ERROR | Grid switch error | + | INTERNAL_ERROR | Internal server or UMA error | + enum: + - GRID_SWITCH_ERROR + - INTERNAL_ERROR + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + FeeRuleCreateRequest: + type: object + description: Request body for creating a new platform fee rule. + required: + - transactionType + - feeType + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + feeType: + $ref: '#/components/schemas/FeeRuleType' + fixedFee: + type: integer + format: int64 + description: Fixed fee in the smallest unit of USD (cents). Required when feeType is FIXED or HYBRID. Must be between 0 and 10000 ($100.00). + minimum: 0 + maximum: 10000 + example: 150 + variableFeeRate: + type: number + format: double + description: Variable fee as a decimal rate (e.g., 0.005 = 0.5%). Required when feeType is PERCENTAGE or HYBRID. Must be between 0 and 0.20 (20%). + minimum: 0 + maximum: 0.2 + example: 0.005 + enabled: + type: boolean + description: Whether the rule should be active immediately. Defaults to true. + default: true + example: true + Error409: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 409 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL | Transaction is not pending platform approval | + | UMA_ADDRESS_EXISTS | UMA address already exists | + | FEE_RULE_EXISTS | A fee rule for this transaction type already exists | + enum: + - TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL + - UMA_ADDRESS_EXISTS + - FEE_RULE_EXISTS + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + Error404: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 404 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | TRANSACTION_NOT_FOUND | Transaction not found | + | INVITATION_NOT_FOUND | Invitation not found | + | USER_NOT_FOUND | Customer not found | + | QUOTE_NOT_FOUND | Quote not found | + | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found | + | TOKEN_NOT_FOUND | Token not found | + | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | + | REFERENCE_NOT_FOUND | Reference not found | + | FEE_RULE_NOT_FOUND | Fee rule not found | + enum: + - TRANSACTION_NOT_FOUND + - INVITATION_NOT_FOUND + - USER_NOT_FOUND + - QUOTE_NOT_FOUND + - LOOKUP_REQUEST_NOT_FOUND + - TOKEN_NOT_FOUND + - BULK_UPLOAD_JOB_NOT_FOUND + - REFERENCE_NOT_FOUND + - FEE_RULE_NOT_FOUND + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true + FeeRulePatchRequest: + type: object + description: Partial update for an existing fee rule. Only provided fields are updated. The transactionType and feeType cannot be changed — delete and recreate the rule instead. + properties: + fixedFee: + type: integer + format: int64 + description: Updated fixed fee in the smallest unit of USD (cents). Must be between 0 and 10000. + minimum: 0 + maximum: 10000 + example: 200 + variableFeeRate: + type: number + format: double + description: Updated variable fee as a decimal rate. Must be between 0 and 0.20. + minimum: 0 + maximum: 0.2 + example: 0.01 + enabled: + type: boolean + description: Enable or disable the fee rule + example: false + FeeReportLine: + type: object + description: Aggregated platform fee revenue for a single transaction type within a reporting period. + required: + - transactionType + - transactionCount + - platformFeesCollected + - currency + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + transactionCount: + type: integer + description: Number of settled transactions that incurred this fee + minimum: 0 + example: 342 + platformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 51300 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + FeeReport: + type: object + description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. + required: + - month + - totalPlatformFeesCollected + - currency + - lines + properties: + month: + type: string + description: Reporting month in YYYY-MM format. + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + totalPlatformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 128450 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + lines: + type: array + description: Per-transaction-type breakdown of collected fees + items: + $ref: '#/components/schemas/FeeReportLine' + CustomerInfoFieldName: + type: string + enum: + - FULL_NAME + - BIRTH_DATE + - NATIONALITY + - PHONE_NUMBER + - EMAIL + - POSTAL_ADDRESS + - TAX_ID + - REGISTRATION_NUMBER + - USER_TYPE + - COUNTRY_OF_RESIDENCE + - ACCOUNT_IDENTIFIER + - FI_LEGAL_ENTITY_NAME + - FI_ADDRESS + - PURPOSE_OF_PAYMENT + - ULTIMATE_INSTITUTION_COUNTRY + - IDENTIFIER + description: Name of a type of field containing info about a platform's customer or counterparty customer. + example: FULL_NAME + CounterpartyFieldDefinition: + type: object + properties: + name: + $ref: '#/components/schemas/CustomerInfoFieldName' + mandatory: + type: boolean + description: Whether the field is mandatory + example: true + required: + - name + - mandatory + TransactionType: + type: string + enum: + - INCOMING + - OUTGOING + description: Type of transaction (incoming payment or outgoing payment) + PlatformCurrencyConfig: type: object properties: currencyCode: @@ -4073,143 +4786,6 @@ components: description: Last update timestamp readOnly: true example: '2025-06-15T12:30:45Z' - Error401: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 401 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | UNAUTHORIZED | Issue with API credentials | - | INVALID_SIGNATURE | Signature header is invalid | - enum: - - UNAUTHORIZED - - INVALID_SIGNATURE - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error500: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 500 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | GRID_SWITCH_ERROR | Grid switch error | - | INTERNAL_ERROR | Internal server or UMA error | - enum: - - GRID_SWITCH_ERROR - - INTERNAL_ERROR - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error400: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 400 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | INVALID_INPUT | Invalid input provided | - | MISSING_MANDATORY_USER_INFO | Required customer information is missing | - | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed | - | INVITATIONS_NOT_CONFIGURED | Invitations are not configured | - | INVALID_UMA_ADDRESS | UMA address format is invalid | - | INVITATION_CANCELLED | Invitation has been cancelled | - | QUOTE_REQUEST_FAILED | An issue occurred during the quote process; this is retryable | - | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid | - | INVALID_RECEIVER | Receiver is invalid | - | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response | - | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid | - | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired | - | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid | - | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing | - | SENDER_NOT_ACCEPTED | Sender is not accepted | - | AMOUNT_OUT_OF_RANGE | Amount is out of range | - | INVALID_CURRENCY | Currency is invalid | - | INVALID_TIMESTAMP | Timestamp is invalid | - | INVALID_NONCE | Nonce is invalid | - | INVALID_REQUEST_FORMAT | Request format is invalid | - | INVALID_BANK_ACCOUNT | Bank account is invalid | - | SELF_PAYMENT | Self payment not allowed | - | LOOKUP_REQUEST_FAILED | Lookup request failed | - | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response | - | INVALID_AMOUNT | Amount is invalid | - | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | - | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | - enum: - - INVALID_INPUT - - MISSING_MANDATORY_USER_INFO - - INVITATION_ALREADY_CLAIMED - - INVITATIONS_NOT_CONFIGURED - - INVALID_UMA_ADDRESS - - INVITATION_CANCELLED - - QUOTE_REQUEST_FAILED - - INVALID_PAYREQ_RESPONSE - - INVALID_RECEIVER - - PARSE_PAYREQ_RESPONSE_ERROR - - CERT_CHAIN_INVALID - - CERT_CHAIN_EXPIRED - - INVALID_PUBKEY_FORMAT - - MISSING_REQUIRED_UMA_PARAMETERS - - SENDER_NOT_ACCEPTED - - AMOUNT_OUT_OF_RANGE - - INVALID_CURRENCY - - INVALID_TIMESTAMP - - INVALID_NONCE - - INVALID_REQUEST_FORMAT - - INVALID_BANK_ACCOUNT - - SELF_PAYMENT - - LOOKUP_REQUEST_FAILED - - PARSE_LNURLP_RESPONSE_ERROR - - INVALID_AMOUNT - - WEBHOOK_ENDPOINT_NOT_SET - - WEBHOOK_DELIVERY_ERROR - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true Error501: type: object required: @@ -4620,76 +5196,6 @@ components: mapping: INDIVIDUAL: '#/components/schemas/IndividualCustomerCreateRequest' BUSINESS: '#/components/schemas/BusinessCustomerCreateRequest' - Error409: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 409 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL | Transaction is not pending platform approval | - | UMA_ADDRESS_EXISTS | UMA address already exists | - enum: - - TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL - - UMA_ADDRESS_EXISTS - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true - Error404: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 404 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | TRANSACTION_NOT_FOUND | Transaction not found | - | INVITATION_NOT_FOUND | Invitation not found | - | USER_NOT_FOUND | Customer not found | - | QUOTE_NOT_FOUND | Quote not found | - | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found | - | TOKEN_NOT_FOUND | Token not found | - | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | - | REFERENCE_NOT_FOUND | Reference not found | - enum: - - TRANSACTION_NOT_FOUND - - INVITATION_NOT_FOUND - - USER_NOT_FOUND - - QUOTE_NOT_FOUND - - LOOKUP_REQUEST_NOT_FOUND - - TOKEN_NOT_FOUND - - BULK_UPLOAD_JOB_NOT_FOUND - - REFERENCE_NOT_FOUND - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true Error410: type: object required: @@ -6003,6 +6509,24 @@ components: description: The variable fee amount charged by the Grid product to execute the quote in the smallest unit of the receiving currency (eg. cents). This is the receiving amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: The fixed fee configured by the platform for this transaction type, in the smallest unit of USD (cents). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: The variable fee rate configured by the platform as a decimal (e.g., 0.005 = 0.5%). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: The calculated variable fee amount from the platform's fee rule, in the smallest unit of the receiving currency (eg. cents). This is the receiving amount times platformVariableFeeRate. Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 50 IncomingTransactionFailureReason: type: string enum: @@ -6103,6 +6627,24 @@ components: description: The variable fee amount charged by the Grid product to execute the quote in the smallest unit of the sending currency (eg. cents). This is the sending amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: The fixed fee configured by the platform for this transaction type, in the smallest unit of USD (cents). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: The variable fee rate configured by the platform as a decimal (e.g., 0.005 = 0.5%). Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: The calculated variable fee amount from the platform's fee rule, in the smallest unit of the sending currency (eg. cents). This is the sending amount times platformVariableFeeRate. Only present when the platform has an active fee rule for this transaction type. + minimum: 0 + example: 50 OutgoingTransactionFailureReason: type: string enum: diff --git a/openapi/components/schemas/errors/Error400.yaml b/openapi/components/schemas/errors/Error400.yaml index 804857b9..4189dd6f 100644 --- a/openapi/components/schemas/errors/Error400.yaml +++ b/openapi/components/schemas/errors/Error400.yaml @@ -41,6 +41,8 @@ properties: | INVALID_AMOUNT | Amount is invalid | | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | + | INVALID_FEE_RULE | Fee rule input is invalid (missing fields, amounts out of range, or wrong feeType/field combination) | + | INVALID_MONTH_FORMAT | Month parameter must be in YYYY-MM format | enum: - INVALID_INPUT - MISSING_MANDATORY_USER_INFO @@ -69,6 +71,8 @@ properties: - INVALID_AMOUNT - WEBHOOK_ENDPOINT_NOT_SET - WEBHOOK_DELIVERY_ERROR + - INVALID_FEE_RULE + - INVALID_MONTH_FORMAT message: type: string description: Error message diff --git a/openapi/components/schemas/errors/Error404.yaml b/openapi/components/schemas/errors/Error404.yaml index d53ff414..98f12ad5 100644 --- a/openapi/components/schemas/errors/Error404.yaml +++ b/openapi/components/schemas/errors/Error404.yaml @@ -22,6 +22,7 @@ properties: | TOKEN_NOT_FOUND | Token not found | | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | | REFERENCE_NOT_FOUND | Reference not found | + | FEE_RULE_NOT_FOUND | Fee rule not found | enum: - TRANSACTION_NOT_FOUND - INVITATION_NOT_FOUND @@ -31,6 +32,7 @@ properties: - TOKEN_NOT_FOUND - BULK_UPLOAD_JOB_NOT_FOUND - REFERENCE_NOT_FOUND + - FEE_RULE_NOT_FOUND message: type: string description: Error message diff --git a/openapi/components/schemas/errors/Error409.yaml b/openapi/components/schemas/errors/Error409.yaml index b033a67f..b03afc1c 100644 --- a/openapi/components/schemas/errors/Error409.yaml +++ b/openapi/components/schemas/errors/Error409.yaml @@ -16,9 +16,11 @@ properties: |------------|-------------| | TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL | Transaction is not pending platform approval | | UMA_ADDRESS_EXISTS | UMA address already exists | + | FEE_RULE_EXISTS | A fee rule for this transaction type already exists | enum: - TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL - UMA_ADDRESS_EXISTS + - FEE_RULE_EXISTS message: type: string description: Error message diff --git a/openapi/components/schemas/fee_rules/FeeReport.yaml b/openapi/components/schemas/fee_rules/FeeReport.yaml new file mode 100644 index 00000000..ddb02445 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeReport.yaml @@ -0,0 +1,35 @@ +type: object +description: >- + Monthly summary of platform fee revenue, broken down by transaction type. + Covers fees collected in real time during transaction settlement within the + specified month. +required: + - month + - totalPlatformFeesCollected + - currency + - lines +properties: + month: + type: string + description: >- + Reporting month in YYYY-MM format. + pattern: '^\d{4}-\d{2}$' + example: '2026-02' + totalPlatformFeesCollected: + type: integer + format: int64 + description: >- + Total platform fees collected across all transaction types in the + smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 128450 + currency: + type: string + description: >- + ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + lines: + type: array + description: Per-transaction-type breakdown of collected fees + items: + $ref: ./FeeReportLine.yaml diff --git a/openapi/components/schemas/fee_rules/FeeReportLine.yaml b/openapi/components/schemas/fee_rules/FeeReportLine.yaml new file mode 100644 index 00000000..ec09a527 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeReportLine.yaml @@ -0,0 +1,30 @@ +type: object +description: >- + Aggregated platform fee revenue for a single transaction type within a + reporting period. +required: + - transactionType + - transactionCount + - platformFeesCollected + - currency +properties: + transactionType: + $ref: ./FeeTransactionType.yaml + transactionCount: + type: integer + description: Number of settled transactions that incurred this fee + minimum: 0 + example: 342 + platformFeesCollected: + type: integer + format: int64 + description: >- + Total platform fees collected for this transaction type in the smallest + unit of the reporting currency (USD cents). + minimum: 0 + example: 51300 + currency: + type: string + description: >- + ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD diff --git a/openapi/components/schemas/fee_rules/FeeRule.yaml b/openapi/components/schemas/fee_rules/FeeRule.yaml new file mode 100644 index 00000000..028c9436 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeRule.yaml @@ -0,0 +1,59 @@ +type: object +description: >- + A platform fee rule defines the markup a platform charges its customers + on a specific transaction type, on top of Lightspark and counterparty fees. + Rules are evaluated at quote creation and the resulting platform fee is + collected in real time during settlement. +required: + - id + - transactionType + - feeType + - enabled + - createdAt + - updatedAt +properties: + id: + type: string + description: System-generated unique identifier + readOnly: true + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 + transactionType: + $ref: ./FeeTransactionType.yaml + feeType: + $ref: ./FeeRuleType.yaml + 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 + example: 150 + variableFeeRate: + type: number + format: double + 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. + minimum: 0 + maximum: 0.20 + example: 0.005 + enabled: + type: boolean + description: >- + Whether this fee rule is actively applied to new transactions. Disabled + rules are retained for reporting but do not affect new quotes. + example: true + createdAt: + type: string + format: date-time + description: When the fee rule was created + readOnly: true + example: '2026-01-15T00:00:00Z' + updatedAt: + type: string + format: date-time + description: When the fee rule was last modified + readOnly: true + example: '2026-02-01T12:30:00Z' diff --git a/openapi/components/schemas/fee_rules/FeeRuleCreateRequest.yaml b/openapi/components/schemas/fee_rules/FeeRuleCreateRequest.yaml new file mode 100644 index 00000000..e77a6964 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeRuleCreateRequest.yaml @@ -0,0 +1,34 @@ +type: object +description: Request body for creating a new platform fee rule. +required: + - transactionType + - feeType +properties: + transactionType: + $ref: ./FeeTransactionType.yaml + feeType: + $ref: ./FeeRuleType.yaml + fixedFee: + type: integer + format: int64 + description: >- + Fixed fee in the smallest unit of USD (cents). Required when feeType + is FIXED or HYBRID. Must be between 0 and 10000 ($100.00). + minimum: 0 + maximum: 10000 + example: 150 + variableFeeRate: + type: number + format: double + description: >- + Variable fee as a decimal rate (e.g., 0.005 = 0.5%). Required when + feeType is PERCENTAGE or HYBRID. Must be between 0 and 0.20 (20%). + minimum: 0 + maximum: 0.20 + example: 0.005 + enabled: + type: boolean + description: >- + Whether the rule should be active immediately. Defaults to true. + default: true + example: true diff --git a/openapi/components/schemas/fee_rules/FeeRulePatchRequest.yaml b/openapi/components/schemas/fee_rules/FeeRulePatchRequest.yaml new file mode 100644 index 00000000..6ddea703 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeRulePatchRequest.yaml @@ -0,0 +1,27 @@ +type: object +description: >- + Partial update for an existing fee rule. Only provided fields are updated. + The transactionType and feeType cannot be changed — delete and recreate + the rule instead. +properties: + fixedFee: + type: integer + format: int64 + description: >- + Updated fixed fee in the smallest unit of USD (cents). Must be + between 0 and 10000. + minimum: 0 + maximum: 10000 + example: 200 + variableFeeRate: + type: number + format: double + description: >- + Updated variable fee as a decimal rate. Must be between 0 and 0.20. + minimum: 0 + maximum: 0.20 + example: 0.01 + enabled: + type: boolean + description: Enable or disable the fee rule + example: false diff --git a/openapi/components/schemas/fee_rules/FeeRuleType.yaml b/openapi/components/schemas/fee_rules/FeeRuleType.yaml new file mode 100644 index 00000000..1f90d186 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeRuleType.yaml @@ -0,0 +1,10 @@ +type: string +description: >- + Determines which fee components apply. FIXED charges a flat amount per + transaction. PERCENTAGE charges a rate of the transaction amount. + HYBRID applies both a fixed amount and a percentage rate. +enum: + - FIXED + - PERCENTAGE + - HYBRID +example: HYBRID diff --git a/openapi/components/schemas/fee_rules/FeeTransactionType.yaml b/openapi/components/schemas/fee_rules/FeeTransactionType.yaml new file mode 100644 index 00000000..14777814 --- /dev/null +++ b/openapi/components/schemas/fee_rules/FeeTransactionType.yaml @@ -0,0 +1,12 @@ +type: string +description: >- + The type of transaction the fee rule applies to. Platform fee rules + are scoped to a single transaction type — only one rule per type is + allowed. +enum: + - TRANSFER_IN + - TRANSFER_OUT + - RAMP_ON + - RAMP_OFF + - CROSS_BORDER_PAYOUT +example: CROSS_BORDER_PAYOUT diff --git a/openapi/components/schemas/transactions/IncomingRateDetails.yaml b/openapi/components/schemas/transactions/IncomingRateDetails.yaml index 26a95597..58a0742b 100644 --- a/openapi/components/schemas/transactions/IncomingRateDetails.yaml +++ b/openapi/components/schemas/transactions/IncomingRateDetails.yaml @@ -39,3 +39,31 @@ properties: receiving amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: >- + The fixed fee configured by the platform for this transaction type, in the + smallest unit of USD (cents). Only present when the platform has an active + fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: >- + The variable fee rate configured by the platform as a decimal + (e.g., 0.005 = 0.5%). Only present when the platform has an active + fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: >- + The calculated variable fee amount from the platform's fee rule, in the + smallest unit of the receiving currency (eg. cents). This is the receiving + amount times platformVariableFeeRate. Only present when the platform has + an active fee rule for this transaction type. + minimum: 0 + example: 50 diff --git a/openapi/components/schemas/transactions/OutgoingRateDetails.yaml b/openapi/components/schemas/transactions/OutgoingRateDetails.yaml index e6beff62..53b375fe 100644 --- a/openapi/components/schemas/transactions/OutgoingRateDetails.yaml +++ b/openapi/components/schemas/transactions/OutgoingRateDetails.yaml @@ -57,3 +57,31 @@ properties: sending amount times gridApiVariableFeeRate. minimum: 0 example: 30 + platformFixedFee: + type: integer + format: int64 + description: >- + The fixed fee configured by the platform for this transaction type, in the + smallest unit of USD (cents). Only present when the platform has an active + fee rule for this transaction type. + minimum: 0 + example: 150 + platformVariableFeeRate: + type: number + format: double + description: >- + The variable fee rate configured by the platform as a decimal + (e.g., 0.005 = 0.5%). Only present when the platform has an active + fee rule for this transaction type. + minimum: 0 + example: 0.005 + platformVariableFeeAmount: + type: integer + format: int64 + description: >- + The calculated variable fee amount from the platform's fee rule, in the + smallest unit of the sending currency (eg. cents). This is the sending + amount times platformVariableFeeRate. Only present when the platform has + an active fee rule for this transaction type. + minimum: 0 + example: 50 diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 45d66a13..784eebcf 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -35,6 +35,11 @@ tags: description: Endpoints to trigger test cases in sandbox - name: API Tokens description: Endpoints to programmatically manage API tokens + - name: Platform Fee Rules + description: >- + Configure the markup your platform charges customers on each transaction + type. Platform fees are layered on top of Lightspark and counterparty + fees and collected in real time during settlement. - name: Exchange Rates description: >- Endpoints for retrieving cached foreign exchange rates. Rates are cached @@ -86,6 +91,12 @@ components: - $ref: components/schemas/errors/Error500.yaml - $ref: components/schemas/errors/Error501.yaml paths: + /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 /config: $ref: paths/platform/config.yaml /exchange-rates: diff --git a/openapi/paths/fee-rules/fee_rules.yaml b/openapi/paths/fee-rules/fee_rules.yaml new file mode 100644 index 00000000..03f7b7b5 --- /dev/null +++ b/openapi/paths/fee-rules/fee_rules.yaml @@ -0,0 +1,141 @@ +post: + summary: Create a fee rule + description: > + Create a platform fee rule for a specific transaction type. The rule defines + the markup your platform charges customers on top of Lightspark and + counterparty fees. Only one rule per transaction type is allowed. + + + Fee rules are evaluated at quote creation time. The resulting platform fee is + included in the quote's `rateDetails` and collected in real time during + settlement — no manual reconciliation is needed. + + + **Fee types:** + + - `FIXED` — a flat amount per transaction (requires `fixedFee`) + + - `PERCENTAGE` — a rate of the transaction amount (requires `variableFeeRate`) + + - `HYBRID` — both a fixed amount and a percentage rate (requires both) + operationId: createFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeRuleCreateRequest.yaml + examples: + fixedFee: + summary: Fixed fee of $1.50 on transfers out + value: + transactionType: TRANSFER_OUT + feeType: FIXED + fixedFee: 150 + percentageFee: + summary: 0.5% fee on cross-border payouts + value: + transactionType: CROSS_BORDER_PAYOUT + feeType: PERCENTAGE + variableFeeRate: 0.005 + hybridFee: + summary: $1.50 + 0.5% on off-ramps + value: + transactionType: RAMP_OFF + feeType: HYBRID + fixedFee: 150 + variableFeeRate: 0.005 + responses: + '201': + description: Fee rule created successfully + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeRule.yaml + '400': + description: >- + Invalid input — missing required fields, invalid feeType, or fee + amounts out of range + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '409': + description: A fee rule for this transaction type already exists + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error409.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml +get: + summary: List fee rules + description: > + Retrieve all platform fee rules. Returns the complete set of configured + rules. Since the maximum number of rules is bounded by the number of + transaction types (5), pagination is not required. + operationId: listFeeRules + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: transactionType + in: query + description: Filter by transaction type + required: false + schema: + $ref: ../../components/schemas/fee_rules/FeeTransactionType.yaml + - name: enabled + in: query + description: Filter by enabled status + required: false + schema: + type: boolean + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + description: List of platform fee rules + items: + $ref: ../../components/schemas/fee_rules/FeeRule.yaml + '400': + description: Bad request — invalid query parameters + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml diff --git a/openapi/paths/fee-rules/fee_rules_report.yaml b/openapi/paths/fee-rules/fee_rules_report.yaml new file mode 100644 index 00000000..8ef26b57 --- /dev/null +++ b/openapi/paths/fee-rules/fee_rules_report.yaml @@ -0,0 +1,70 @@ +get: + summary: Get monthly fee report + description: > + Retrieve an aggregated summary of platform fees collected during a specific + month, broken down by transaction type. Covers only transaction-based fees + that were collected in real time during settlement. + + + The report includes the total fees collected and a per-transaction-type + breakdown with transaction counts. + operationId: getFeeReport + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: month + in: query + description: >- + Reporting month in YYYY-MM format. Defaults to the current month. + required: false + schema: + type: string + pattern: '^\d{4}-\d{2}$' + example: '2026-02' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeReport.yaml + examples: + monthlyReport: + summary: February 2026 fee report + value: + month: '2026-02' + totalPlatformFeesCollected: 128450 + currency: USD + lines: + - transactionType: TRANSFER_OUT + transactionCount: 245 + platformFeesCollected: 62500 + currency: USD + - transactionType: CROSS_BORDER_PAYOUT + transactionCount: 97 + platformFeesCollected: 51300 + currency: USD + - transactionType: RAMP_OFF + transactionCount: 58 + platformFeesCollected: 14650 + currency: USD + '400': + description: Invalid month format + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml diff --git a/openapi/paths/fee-rules/fee_rules_{feeRuleId}.yaml b/openapi/paths/fee-rules/fee_rules_{feeRuleId}.yaml new file mode 100644 index 00000000..4428dad7 --- /dev/null +++ b/openapi/paths/fee-rules/fee_rules_{feeRuleId}.yaml @@ -0,0 +1,130 @@ +parameters: + - name: feeRuleId + in: path + description: System-generated unique fee rule identifier + required: true + schema: + type: string + example: FeeRule:019c6a2b-4f8e-7d01-0000-000000000001 +get: + summary: Get fee rule by ID + description: Retrieve a single platform fee rule by its system-generated ID. + operationId: getFeeRuleById + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeRule.yaml + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error404.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml +patch: + summary: Update a fee rule + description: > + Partially update an existing fee rule. Only the provided fields are + modified. The `transactionType` and `feeType` cannot be changed — delete + and recreate the rule instead. + operationId: updateFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeRulePatchRequest.yaml + examples: + disableRule: + summary: Disable a fee rule + value: + enabled: false + updateFee: + summary: Update fixed fee amount + value: + fixedFee: 200 + responses: + '200': + description: Fee rule updated successfully + content: + application/json: + schema: + $ref: ../../components/schemas/fee_rules/FeeRule.yaml + '400': + description: Invalid input — fee amounts out of range + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error400.yaml + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error404.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml +delete: + summary: Delete a fee rule + description: > + Delete a platform fee rule. Future transactions of this type will no longer + include a platform markup. Transactions already in progress or settled are + unaffected. + operationId: deleteFeeRule + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + responses: + '204': + description: Fee rule deleted successfully + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error401.yaml + '404': + description: Fee rule not found + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error404.yaml + '500': + description: Internal service error + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error500.yaml From 9a66dbe3811b02655e7684cabc22c40d4a8745fa Mon Sep 17 00:00:00 2001 From: jaymantri Date: Wed, 18 Feb 2026 09:15:40 -0800 Subject: [PATCH 2/2] fix: resolve Stainless SDK regressions and doc example mismatch - 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 --- mintlify/openapi.yaml | 244 +++++++++++------------ mintlify/snippets/platform-fee-rules.mdx | 8 +- openapi.yaml | 244 +++++++++++------------ openapi/openapi.yaml | 4 +- openapi/paths/fee-rules/fee_rules.yaml | 2 +- 5 files changed, 253 insertions(+), 249 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 2753aba6..1c359f2b 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -121,7 +121,7 @@ paths: summary: List fee rules description: | Retrieve all platform fee rules. Returns the complete set of configured rules. Since the maximum number of rules is bounded by the number of transaction types (5), pagination is not required. - operationId: listFeeRules + operationId: getFeeRules tags: - Platform Fee Rules security: @@ -172,6 +172,72 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /fee-rules/report: + get: + summary: Get monthly fee report + description: | + Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. + + The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. + operationId: getFeeReport + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: month + in: query + description: Reporting month in YYYY-MM format. Defaults to the current month. + required: false + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeReport' + examples: + monthlyReport: + summary: February 2026 fee report + value: + month: 2026-02 + totalPlatformFeesCollected: 128450 + currency: USD + lines: + - transactionType: TRANSFER_OUT + transactionCount: 245 + platformFeesCollected: 62500 + currency: USD + - transactionType: CROSS_BORDER_PAYOUT + transactionCount: 97 + platformFeesCollected: 51300 + currency: USD + - transactionType: RAMP_OFF + transactionCount: 58 + platformFeesCollected: 14650 + currency: USD + '400': + description: Invalid month format + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /fee-rules/{feeRuleId}: parameters: - name: feeRuleId @@ -299,72 +365,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' - /fee-rules/report: - get: - summary: Get monthly fee report - description: | - Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. - - The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. - operationId: getFeeReport - tags: - - Platform Fee Rules - security: - - BasicAuth: [] - parameters: - - name: month - in: query - description: Reporting month in YYYY-MM format. Defaults to the current month. - required: false - schema: - type: string - pattern: ^\d{4}-\d{2}$ - example: 2026-02 - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/FeeReport' - examples: - monthlyReport: - summary: February 2026 fee report - value: - month: 2026-02 - totalPlatformFeesCollected: 128450 - currency: USD - lines: - - transactionType: TRANSFER_OUT - transactionCount: 245 - platformFeesCollected: 62500 - currency: USD - - transactionType: CROSS_BORDER_PAYOUT - transactionCount: 97 - platformFeesCollected: 51300 - currency: USD - - transactionType: RAMP_OFF - transactionCount: 58 - platformFeesCollected: 14650 - currency: USD - '400': - description: Invalid month format - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' /config: get: summary: Get platform configuration @@ -4517,6 +4517,61 @@ components: type: object description: Additional error details additionalProperties: true + FeeReportLine: + type: object + description: Aggregated platform fee revenue for a single transaction type within a reporting period. + required: + - transactionType + - transactionCount + - platformFeesCollected + - currency + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + transactionCount: + type: integer + description: Number of settled transactions that incurred this fee + minimum: 0 + example: 342 + platformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 51300 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + FeeReport: + type: object + description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. + required: + - month + - totalPlatformFeesCollected + - currency + - lines + properties: + month: + type: string + description: Reporting month in YYYY-MM format. + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + totalPlatformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 128450 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + lines: + type: array + description: Per-transaction-type breakdown of collected fees + items: + $ref: '#/components/schemas/FeeReportLine' Error404: type: object required: @@ -4582,61 +4637,6 @@ components: type: boolean description: Enable or disable the fee rule example: false - FeeReportLine: - type: object - description: Aggregated platform fee revenue for a single transaction type within a reporting period. - required: - - transactionType - - transactionCount - - platformFeesCollected - - currency - properties: - transactionType: - $ref: '#/components/schemas/FeeTransactionType' - transactionCount: - type: integer - description: Number of settled transactions that incurred this fee - minimum: 0 - example: 342 - platformFeesCollected: - type: integer - format: int64 - description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). - minimum: 0 - example: 51300 - currency: - type: string - description: ISO 4217 currency code for the reporting currency. Currently always USD. - example: USD - FeeReport: - type: object - description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. - required: - - month - - totalPlatformFeesCollected - - currency - - lines - properties: - month: - type: string - description: Reporting month in YYYY-MM format. - pattern: ^\d{4}-\d{2}$ - example: 2026-02 - totalPlatformFeesCollected: - type: integer - format: int64 - description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). - minimum: 0 - example: 128450 - currency: - type: string - description: ISO 4217 currency code for the reporting currency. Currently always USD. - example: USD - lines: - type: array - description: Per-transaction-type breakdown of collected fees - items: - $ref: '#/components/schemas/FeeReportLine' CustomerInfoFieldName: type: string enum: diff --git a/mintlify/snippets/platform-fee-rules.mdx b/mintlify/snippets/platform-fee-rules.mdx index 916cf84d..6603b9ff 100644 --- a/mintlify/snippets/platform-fee-rules.mdx +++ b/mintlify/snippets/platform-fee-rules.mdx @@ -1,5 +1,3 @@ -import { gridBaseUrl } from '/snippets/variables.mdx'; - Platform fee rules let you define the markup your platform charges customers on each transaction type. Fees are layered on top of Lightspark and counterparty fees, and collected in real time during settlement. @@ -144,6 +142,12 @@ curl https://api.lightspark.com/grid/2025-10-13/fee-rules/report?month=2026-02 \ "transactionCount": 245, "platformFeesCollected": 62500, "currency": "USD" + }, + { + "transactionType": "RAMP_OFF", + "transactionCount": 58, + "platformFeesCollected": 14650, + "currency": "USD" } ] } diff --git a/openapi.yaml b/openapi.yaml index 2753aba6..1c359f2b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -121,7 +121,7 @@ paths: summary: List fee rules description: | Retrieve all platform fee rules. Returns the complete set of configured rules. Since the maximum number of rules is bounded by the number of transaction types (5), pagination is not required. - operationId: listFeeRules + operationId: getFeeRules tags: - Platform Fee Rules security: @@ -172,6 +172,72 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + /fee-rules/report: + get: + summary: Get monthly fee report + description: | + Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. + + The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. + operationId: getFeeReport + tags: + - Platform Fee Rules + security: + - BasicAuth: [] + parameters: + - name: month + in: query + description: Reporting month in YYYY-MM format. Defaults to the current month. + required: false + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/FeeReport' + examples: + monthlyReport: + summary: February 2026 fee report + value: + month: 2026-02 + totalPlatformFeesCollected: 128450 + currency: USD + lines: + - transactionType: TRANSFER_OUT + transactionCount: 245 + platformFeesCollected: 62500 + currency: USD + - transactionType: CROSS_BORDER_PAYOUT + transactionCount: 97 + platformFeesCollected: 51300 + currency: USD + - transactionType: RAMP_OFF + transactionCount: 58 + platformFeesCollected: 14650 + currency: USD + '400': + description: Invalid month format + content: + application/json: + schema: + $ref: '#/components/schemas/Error400' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error401' + '500': + description: Internal service error + content: + application/json: + schema: + $ref: '#/components/schemas/Error500' /fee-rules/{feeRuleId}: parameters: - name: feeRuleId @@ -299,72 +365,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' - /fee-rules/report: - get: - summary: Get monthly fee report - description: | - Retrieve an aggregated summary of platform fees collected during a specific month, broken down by transaction type. Covers only transaction-based fees that were collected in real time during settlement. - - The report includes the total fees collected and a per-transaction-type breakdown with transaction counts. - operationId: getFeeReport - tags: - - Platform Fee Rules - security: - - BasicAuth: [] - parameters: - - name: month - in: query - description: Reporting month in YYYY-MM format. Defaults to the current month. - required: false - schema: - type: string - pattern: ^\d{4}-\d{2}$ - example: 2026-02 - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/FeeReport' - examples: - monthlyReport: - summary: February 2026 fee report - value: - month: 2026-02 - totalPlatformFeesCollected: 128450 - currency: USD - lines: - - transactionType: TRANSFER_OUT - transactionCount: 245 - platformFeesCollected: 62500 - currency: USD - - transactionType: CROSS_BORDER_PAYOUT - transactionCount: 97 - platformFeesCollected: 51300 - currency: USD - - transactionType: RAMP_OFF - transactionCount: 58 - platformFeesCollected: 14650 - currency: USD - '400': - description: Invalid month format - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' /config: get: summary: Get platform configuration @@ -4517,6 +4517,61 @@ components: type: object description: Additional error details additionalProperties: true + FeeReportLine: + type: object + description: Aggregated platform fee revenue for a single transaction type within a reporting period. + required: + - transactionType + - transactionCount + - platformFeesCollected + - currency + properties: + transactionType: + $ref: '#/components/schemas/FeeTransactionType' + transactionCount: + type: integer + description: Number of settled transactions that incurred this fee + minimum: 0 + example: 342 + platformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 51300 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + FeeReport: + type: object + description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. + required: + - month + - totalPlatformFeesCollected + - currency + - lines + properties: + month: + type: string + description: Reporting month in YYYY-MM format. + pattern: ^\d{4}-\d{2}$ + example: 2026-02 + totalPlatformFeesCollected: + type: integer + format: int64 + description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). + minimum: 0 + example: 128450 + currency: + type: string + description: ISO 4217 currency code for the reporting currency. Currently always USD. + example: USD + lines: + type: array + description: Per-transaction-type breakdown of collected fees + items: + $ref: '#/components/schemas/FeeReportLine' Error404: type: object required: @@ -4582,61 +4637,6 @@ components: type: boolean description: Enable or disable the fee rule example: false - FeeReportLine: - type: object - description: Aggregated platform fee revenue for a single transaction type within a reporting period. - required: - - transactionType - - transactionCount - - platformFeesCollected - - currency - properties: - transactionType: - $ref: '#/components/schemas/FeeTransactionType' - transactionCount: - type: integer - description: Number of settled transactions that incurred this fee - minimum: 0 - example: 342 - platformFeesCollected: - type: integer - format: int64 - description: Total platform fees collected for this transaction type in the smallest unit of the reporting currency (USD cents). - minimum: 0 - example: 51300 - currency: - type: string - description: ISO 4217 currency code for the reporting currency. Currently always USD. - example: USD - FeeReport: - type: object - description: Monthly summary of platform fee revenue, broken down by transaction type. Covers fees collected in real time during transaction settlement within the specified month. - required: - - month - - totalPlatformFeesCollected - - currency - - lines - properties: - month: - type: string - description: Reporting month in YYYY-MM format. - pattern: ^\d{4}-\d{2}$ - example: 2026-02 - totalPlatformFeesCollected: - type: integer - format: int64 - description: Total platform fees collected across all transaction types in the smallest unit of the reporting currency (USD cents). - minimum: 0 - example: 128450 - currency: - type: string - description: ISO 4217 currency code for the reporting currency. Currently always USD. - example: USD - lines: - type: array - description: Per-transaction-type breakdown of collected fees - items: - $ref: '#/components/schemas/FeeReportLine' CustomerInfoFieldName: type: string enum: diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 784eebcf..6cdedba6 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -93,10 +93,10 @@ components: paths: /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/{feeRuleId}: + $ref: paths/fee-rules/fee_rules_{feeRuleId}.yaml /config: $ref: paths/platform/config.yaml /exchange-rates: diff --git a/openapi/paths/fee-rules/fee_rules.yaml b/openapi/paths/fee-rules/fee_rules.yaml index 03f7b7b5..76f39489 100644 --- a/openapi/paths/fee-rules/fee_rules.yaml +++ b/openapi/paths/fee-rules/fee_rules.yaml @@ -88,7 +88,7 @@ get: Retrieve all platform fee rules. Returns the complete set of configured rules. Since the maximum number of rules is bounded by the number of transaction types (5), pagination is not required. - operationId: listFeeRules + operationId: getFeeRules tags: - Platform Fee Rules security: