diff --git a/.stainless/stainless.yml b/.stainless/stainless.yml index 627fd145..50105d34 100644 --- a/.stainless/stainless.yml +++ b/.stainless/stainless.yml @@ -81,18 +81,14 @@ resources: customers: models: - # customer_type: '#/components/schemas/CustomerType' - # individual_customer: '#/components/schemas/IndividualCustomer' customer: '#/components/schemas/Customer' - # address: '#/components/schemas/Address' - # ultimate_beneficial_owner: '#/components/schemas/UltimateBeneficialOwner' - # business_customer: '#/components/schemas/BusinessCustomer' - # business_customer_fields: "#/components/schemas/BusinessCustomerFields" - # business_info: "#/components/schemas/BusinessInfo" - # individual_customer_fields: "#/components/schemas/IndividualCustomerFields" customer_one_of: "#/components/schemas/CustomerOneOf" customer_create: "#/components/schemas/CustomerCreateRequest" customer_update: "#/components/schemas/CustomerUpdateRequest" + customer_type: "#/components/schemas/CustomerType" + individual_customer_fields: "#/components/schemas/IndividualCustomerFields" + business_customer_fields: "#/components/schemas/BusinessCustomerFields" + business_info: "#/components/schemas/BusinessInfo" methods: create: endpoint: post /customers @@ -145,12 +141,8 @@ resources: polygon_wallet_info: '#/components/schemas/PolygonWalletExternalAccountInfo' lightning_wallet_info: '#/components/schemas/LightningExternalAccountInfo' base_wallet_info: '#/components/schemas/BaseWalletExternalAccountInfo' - # individual_beneficiary: '#/components/schemas/IndividualBeneficiary' - # business_beneficiary: '#/components/schemas/BusinessBeneficiary' external_account: '#/components/schemas/ExternalAccount' external_account_create: '#/components/schemas/ExternalAccountCreateRequest' - # base_external_account_info: "#/components/schemas/BaseExternalAccountInfo" - # base_beneficiary: "#/components/schemas/BaseBeneficiary" external_account_info_one_of: "#/components/schemas/ExternalAccountInfoOneOf" business_beneficiary: "#/components/schemas/BusinessBeneficiary" address: "#/components/schemas/Address" @@ -175,6 +167,24 @@ resources: endpoint: get /platform/external-accounts paginated: false create: post /platform/external-accounts + models: + usd_account_info: "#/components/schemas/UsdAccountInfo" + brl_account_info: "#/components/schemas/BrlAccountInfo" + mxn_account_info: "#/components/schemas/MxnAccountInfo" + dkk_account_info: "#/components/schemas/DkkAccountInfo" + eur_account_info: "#/components/schemas/EurAccountInfo" + inr_account_info: "#/components/schemas/InrAccountInfo" + ngn_account_info: "#/components/schemas/NgnAccountInfo" + cad_account_info: "#/components/schemas/CadAccountInfo" + gbp_account_info: "#/components/schemas/GbpAccountInfo" + hkd_account_info: "#/components/schemas/HkdAccountInfo" + idr_account_info: "#/components/schemas/IdrAccountInfo" + myr_account_info: "#/components/schemas/MyrAccountInfo" + php_account_info: "#/components/schemas/PhpAccountInfo" + sgd_account_info: "#/components/schemas/SgdAccountInfo" + thb_account_info: "#/components/schemas/ThbAccountInfo" + vnd_account_info: "#/components/schemas/VndAccountInfo" + # base_external_account_info: "#/components/schemas/BaseExternalAccountInfo" plaid: methods: @@ -183,8 +193,10 @@ resources: transfer_in: models: - transaction: '#/components/schemas/Transaction' - #base_transaction_destination: "#/components/schemas/BaseTransactionDestination" + transaction: "#/components/schemas/TransactionOneOf" + base_transaction_destination: "#/components/schemas/BaseTransactionDestination" + external_account_reference: "#/components/schemas/ExternalAccountReference" + internal_account_reference: "#/components/schemas/InternalAccountReference" methods: create: post /transfer-in @@ -207,6 +219,10 @@ resources: outgoing_rate_details: '#/components/schemas/OutgoingRateDetails' quote: '#/components/schemas/Quote' quote_destination_one_of: "#/components/schemas/QuoteDestinationOneOf" + # base_payment_account_info: "#/components/schemas/BasePaymentAccountInfo" + base_quote_source: "#/components/schemas/BaseQuoteSource" + quote_source_one_of: "#/components/schemas/QuoteSourceOneOf" + base_destination: "#/components/schemas/BaseDestination" methods: retrieve: get /quotes/{quoteId} create: post /quotes @@ -218,10 +234,12 @@ resources: transaction_type: '#/components/schemas/TransactionType' incoming_transaction: '#/components/schemas/IncomingTransaction' outgoing_transaction: '#/components/schemas/OutgoingTransaction' - transaction_status: '#/components/schemas/TransactionStatus' outgoing_transaction_status: '#/components/schemas/OutgoingTransactionStatus' - #base_transaction_source: "#/components/schemas/BaseTransactionSource" + transaction_status: '#/components/schemas/TransactionStatus' + base_transaction_source: "#/components/schemas/BaseTransactionSource" transaction_source_one_of: "#/components/schemas/TransactionSourceOneOf" + incoming_rate_details: "#/components/schemas/IncomingRateDetails" + reconciliation_instructions: "#/components/schemas/ReconciliationInstructions" methods: list: get /transactions retrieve: get /transactions/{transactionId} @@ -241,7 +259,6 @@ resources: sandbox: methods: send_funds: post /sandbox/send - send_test: post /webhooks/test subresources: uma: methods: @@ -251,6 +268,9 @@ resources: internal_account: '#/components/schemas/InternalAccount' methods: fund: post /sandbox/internal-accounts/{accountId}/fund + webhooks: + methods: + send_test: post /sandbox/webhooks/test uma_providers: methods: @@ -275,7 +295,7 @@ resources: methods: unwrap: type: webhook_unwrap - discriminator: type + $shared: models: bulk_customer_import_error_entry: "#/components/schemas/BulkCustomerImportErrorEntry" @@ -334,11 +354,27 @@ readme: default: type: request endpoint: post /quotes - params: {} + params: + source: + sourceType: ACCOUNT + accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + lockedCurrencySide: SENDING + lockedCurrencyAmount: 10000 headline: type: request endpoint: post /quotes - params: {} + params: + source: + sourceType: ACCOUNT + accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + lockedCurrencySide: SENDING + lockedCurrencyAmount: 10000 pagination: type: request endpoint: get /customers @@ -464,7 +500,7 @@ openapi: - "$.components.schemas.CustomerUpdateRequest.properties" keys: [ "customerType" ] - # ── accountType: remove from base schemas ── + # # ── accountType: remove from base schemas ── - command: remove reason: >- Remove accountType $ref from base schemas so the inline single-value @@ -476,7 +512,7 @@ openapi: - "$.components.schemas.BasePaymentAccountInfo.properties" keys: [ "accountType" ] - # ── sourceType: remove from base schemas ── + # # ── sourceType: remove from base schemas ── - command: remove reason: >- Remove sourceType $ref from base schemas so the inline single-value @@ -487,7 +523,7 @@ openapi: - "$.components.schemas.BaseQuoteSource.properties" keys: [ "sourceType" ] - # ── destinationType: remove from base schemas ── + # # ── destinationType: remove from base schemas ── - command: remove reason: >- Remove destinationType $ref from base schemas so the inline @@ -506,12 +542,22 @@ openapi: stripping the accountType discriminator, which causes TS2312 errors args: target: - - "$.components.schemas.PaymentClabeAccountInfo.allOf[0]" - - "$.components.schemas.PaymentUsAccountInfo.allOf[0]" - - "$.components.schemas.PaymentPixAccountInfo.allOf[0]" - - "$.components.schemas.PaymentIbanAccountInfo.allOf[0]" - - "$.components.schemas.PaymentUpiAccountInfo.allOf[0]" + - "$.components.schemas.PaymentUsdAccountInfo.allOf[0]" + - "$.components.schemas.PaymentBrlAccountInfo.allOf[0]" + - "$.components.schemas.PaymentMxnAccountInfo.allOf[0]" + - "$.components.schemas.PaymentDkkAccountInfo.allOf[0]" + - "$.components.schemas.PaymentEurAccountInfo.allOf[0]" + - "$.components.schemas.PaymentInrAccountInfo.allOf[0]" - "$.components.schemas.PaymentNgnAccountInfo.allOf[0]" + - "$.components.schemas.PaymentCadAccountInfo.allOf[0]" + - "$.components.schemas.PaymentGbpAccountInfo.allOf[0]" + - "$.components.schemas.PaymentHkdAccountInfo.allOf[0]" + - "$.components.schemas.PaymentIdrAccountInfo.allOf[0]" + - "$.components.schemas.PaymentMyrAccountInfo.allOf[0]" + - "$.components.schemas.PaymentPhpAccountInfo.allOf[0]" + - "$.components.schemas.PaymentSgdAccountInfo.allOf[0]" + - "$.components.schemas.PaymentThbAccountInfo.allOf[0]" + - "$.components.schemas.PaymentVndAccountInfo.allOf[0]" - "$.components.schemas.PaymentSparkWalletInfo.allOf[0]" - "$.components.schemas.PaymentLightningInvoiceInfo.allOf[0]" - "$.components.schemas.PaymentSolanaWalletInfo.allOf[0]" @@ -520,6 +566,46 @@ openapi: - "$.components.schemas.PaymentBaseWalletInfo.allOf[0]" keys: [ "$ref" ] + # ── Remove $ref to BaseExternalAccountInfo from external account variants ── + - command: remove + reason: >- + Remove allOf $ref to BaseExternalAccountInfo from external account info + variants because the base schema becomes an empty object after stripping + the accountType discriminator + args: + target: + - "$.components.schemas.UsdExternalAccountInfo.allOf[0]" + - "$.components.schemas.BrlExternalAccountInfo.allOf[0]" + - "$.components.schemas.MxnExternalAccountInfo.allOf[0]" + - "$.components.schemas.DkkExternalAccountInfo.allOf[0]" + - "$.components.schemas.EurExternalAccountInfo.allOf[0]" + - "$.components.schemas.InrExternalAccountInfo.allOf[0]" + - "$.components.schemas.NgnExternalAccountInfo.allOf[0]" + - "$.components.schemas.CadExternalAccountInfo.allOf[0]" + - "$.components.schemas.GbpExternalAccountInfo.allOf[0]" + - "$.components.schemas.HkdExternalAccountInfo.allOf[0]" + - "$.components.schemas.IdrExternalAccountInfo.allOf[0]" + - "$.components.schemas.MyrExternalAccountInfo.allOf[0]" + - "$.components.schemas.PhpExternalAccountInfo.allOf[0]" + - "$.components.schemas.SgdExternalAccountInfo.allOf[0]" + - "$.components.schemas.ThbExternalAccountInfo.allOf[0]" + - "$.components.schemas.VndExternalAccountInfo.allOf[0]" + - "$.components.schemas.KesExternalAccountInfo.allOf[0]" + - "$.components.schemas.RwfExternalAccountInfo.allOf[0]" + - "$.components.schemas.TzsExternalAccountInfo.allOf[0]" + - "$.components.schemas.ZmwExternalAccountInfo.allOf[0]" + - "$.components.schemas.ZarExternalAccountInfo.allOf[0]" + - "$.components.schemas.XofExternalAccountInfo.allOf[0]" + - "$.components.schemas.MwkExternalAccountInfo.allOf[0]" + - "$.components.schemas.UgxExternalAccountInfo.allOf[0]" + - "$.components.schemas.SparkWalletExternalAccountInfo.allOf[0]" + - "$.components.schemas.LightningExternalAccountInfo.allOf[0]" + - "$.components.schemas.SolanaWalletExternalAccountInfo.allOf[0]" + - "$.components.schemas.TronWalletExternalAccountInfo.allOf[0]" + - "$.components.schemas.PolygonWalletExternalAccountInfo.allOf[0]" + - "$.components.schemas.BaseWalletExternalAccountInfo.allOf[0]" + keys: [ "$ref" ] + # ── Remove $ref to BaseQuoteSource from quote source variants ── - command: remove reason: >- @@ -543,6 +629,30 @@ openapi: - "$.components.schemas.ExternalAccountDetailsDestination.allOf[0]" keys: [ "$ref" ] + # ── Remove $ref to BaseTransactionSource from transaction source variants ── + - command: remove + reason: >- + Remove allOf $ref to BaseTransactionSource from transaction source variants + because the base schema becomes an empty object after stripping sourceType + args: + target: + - "$.components.schemas.AccountTransactionSource.allOf[0]" + - "$.components.schemas.UmaAddressTransactionSource.allOf[0]" + - "$.components.schemas.RealtimeFundingTransactionSource.allOf[0]" + keys: [ "$ref" ] + + # ── Remove $ref to BaseTransactionDestination from transaction destination variants ── + - command: remove + reason: >- + Remove allOf $ref to BaseTransactionDestination from transaction destination + variants because the base schema becomes an empty object after stripping destinationType + args: + target: + - "$.components.schemas.AccountTransactionDestination.allOf[0]" + - "$.components.schemas.UmaAddressTransactionDestination.allOf[0]" + - "$.components.schemas.ExternalAccountDetailsTransactionDestination.allOf[0]" + keys: [ "$ref" ] + codeflow: detect_breaking_changes: true release_environment: npm @@ -552,3 +662,4 @@ diagnostics: - pagination.0.response.data.items Schema/EnumHasOneMember: true Schema/RequiredPropertyNotDefined: true + Schema/IsAmbiguous: true diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 938ee553..0842e59f 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -1623,6 +1623,32 @@ paths: application/json: schema: $ref: '#/components/schemas/Quote' + example: + id: Quote:019542f5-b3e7-1d02-0000-000000000006 + status: PENDING + createdAt: '2025-10-03T12:00:00Z' + expiresAt: '2025-10-03T12:05:00Z' + source: + sourceType: ACCOUNT + accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + sendingCurrency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + receivingCurrency: + code: EUR + name: Euro + symbol: € + decimals: 2 + totalSendingAmount: 10000 + totalReceivingAmount: 9200 + exchangeRate: 0.92 + feesIncluded: 10 + transactionId: Transaction:019542f5-b3e7-1d02-0000-000000000005 '400': description: Bad request - Missing or invalid parameters content: @@ -3517,11 +3543,11 @@ webhooks: application/json: schema: $ref: '#/components/schemas/Error409' - kyc-status: + customer-update: post: - summary: KYC customer status change + summary: Customer status change description: | - Webhook that is called when the KYC status of a customer is updated. + Webhook that is called when the status of a customer is updated, including KYC and KYB status changes. This endpoint should be implemented by clients of the Grid API. ### Authentication @@ -3533,20 +3559,7 @@ webhooks: 4. Verify the signature using the public key and the hash If the signature verification succeeds, the webhook is authentic. If not, it should be rejected. - - ### KYC/B Flow - This webhook is triggered when KYC/B has reached a decision on a customer. Generally most customers will finish KYC within a few minutes. Others might be rejected because of incorrect data passed in or may have been flagged for manual review. - The webhook will only trigger for final states. This will be APPROVED, REJECTED, EXPIRED, CANCELED, MANUALLY_APPROVED, MANUALLY_REJECTED. - - * APPROVED: The customer has been approved. - * REJECTED: The customer has been rejected after a KYC check. - * PENDING_REVIEW: KYC check is in progress. - * EXPIRED: KYC check has expired. This is generally because a customer did not submit all required information needed within a session. - * CANCELED: KYC check was canceled. - * MANUALLY_APPROVED: The customer was manually approved. - * MANUALLY_REJECTED: The customer was manually rejected. - * NOT_STARTED: KYC has not started on the customer. - operationId: kycStatusWebhook + operationId: customerStatusWebhook tags: - Webhooks security: @@ -3556,10 +3569,10 @@ webhooks: content: application/json: schema: - $ref: '#/components/schemas/CustomerKycWebhook' + $ref: '#/components/schemas/CustomerWebhook' examples: kycApprovedWebhook: - summary: When a customer KYC has been approved + summary: When an individual customer KYC has been approved value: id: Webhook:019542f5-b3e7-1d02-0000-000000000007 type: CUSTOMER.KYC_APPROVED @@ -3584,7 +3597,7 @@ webhooks: updatedAt: '2025-07-21T17:32:28Z' isDeleted: false kycRejectedWebhook: - summary: When a customer KYC has been rejected + summary: When an individual customer KYC has been rejected value: id: Webhook:019542f5-b3e7-1d02-0000-000000000008 type: CUSTOMER.KYC_REJECTED @@ -3601,6 +3614,54 @@ webhooks: createdAt: '2025-07-21T17:32:28Z' updatedAt: '2025-08-15T14:32:00Z' isDeleted: false + kybApprovedWebhook: + summary: When a business customer KYB has been approved + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: CUSTOMER.KYB_APPROVED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000003 + platformCustomerId: 7a2f9d4e1b8c3f5 + customerType: BUSINESS + umaAddress: $acme.corp@uma.domain.com + kybStatus: APPROVED + address: + line1: 456 Business Ave + city: New York + state: NY + postalCode: '10001' + country: US + businessInfo: + legalName: Acme Corporation + registrationNumber: '12345678' + taxId: 98-7654321 + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false + kybRejectedWebhook: + summary: When a business customer KYB has been rejected + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000010 + type: CUSTOMER.KYB_REJECTED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000004 + platformCustomerId: 3c8e5f2a9d1b7e4 + customerType: BUSINESS + umaAddress: $globex.inc@uma.domain.com + kybStatus: REJECTED + address: + line1: 789 Corporate Blvd + city: Chicago + state: IL + postalCode: '60601' + country: US + businessInfo: + legalName: Globex Inc + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false responses: '200': description: | @@ -4139,18 +4200,6 @@ components: - BUSINESS description: Whether the customer is an individual or a business entity example: INDIVIDUAL - KycStatus: - type: string - enum: - - APPROVED - - REJECTED - - PENDING_REVIEW - - EXPIRED - - CANCELED - - MANUALLY_APPROVED - - MANUALLY_REJECTED - description: The current KYC status of a customer - example: APPROVED Customer: type: object required: @@ -4169,8 +4218,6 @@ components: example: 9f84e0c2a72c4fa customerType: $ref: '#/components/schemas/CustomerType' - kycStatus: - $ref: '#/components/schemas/KycStatus' umaAddress: type: string description: Full UMA address (always present in responses, even if system-generated). This is an optional identifier to route payments to the customer. @@ -4192,6 +4239,18 @@ components: description: Whether the customer is marked as deleted example: false readOnly: true + KycStatus: + type: string + enum: + - APPROVED + - REJECTED + - PENDING_REVIEW + - EXPIRED + - CANCELED + - MANUALLY_APPROVED + - MANUALLY_REJECTED + description: The current KYC status of a customer + example: APPROVED Address: type: object required: @@ -4232,6 +4291,8 @@ components: type: string enum: - INDIVIDUAL + kycStatus: + $ref: '#/components/schemas/KycStatus' fullName: type: string description: Individual's full name @@ -4252,6 +4313,19 @@ components: allOf: - $ref: '#/components/schemas/Customer' - $ref: '#/components/schemas/IndividualCustomerFields' + KybStatus: + type: string + enum: + - AWAITING_SUBMISSION + - APPROVED + - REJECTED + - PENDING_REVIEW + - EXPIRED + - CANCELED + - MANUALLY_APPROVED + - MANUALLY_REJECTED + description: The current KYB status of a business customer + example: APPROVED BusinessInfoUpdate: type: object description: Additional information for business entities @@ -4331,6 +4405,8 @@ components: type: string enum: - BUSINESS + kybStatus: + $ref: '#/components/schemas/KybStatus' address: $ref: '#/components/schemas/Address' businessInfo: @@ -8824,6 +8900,11 @@ components: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED @@ -8836,7 +8917,6 @@ components: - timestamp - id - type - - data properties: id: type: string @@ -8850,9 +8930,17 @@ components: format: date-time description: ISO 8601 timestamp of when the webhook was sent example: '2025-08-15T14:32:00Z' - data: - type: object - description: The resource object. Contains the full resource as the corresponding GET endpoint would return it. + IncomingPaymentWebhookData: + title: Incoming Payment Webhook Data + allOf: + - $ref: '#/components/schemas/IncomingTransaction' + - type: object + properties: + requestedReceiverCustomerInfoFields: + type: array + items: + $ref: '#/components/schemas/CounterpartyFieldDefinition' + description: Information required by the sender's VASP about the recipient. Platform must provide these in the 200 OK response if approving. Note that this only includes fields which Grid does not already have from initial customer registration. IncomingPaymentWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' @@ -8861,15 +8949,7 @@ components: - data properties: data: - allOf: - - $ref: '#/components/schemas/IncomingTransaction' - - type: object - properties: - requestedReceiverCustomerInfoFields: - type: array - items: - $ref: '#/components/schemas/CounterpartyFieldDefinition' - description: Information required by the sender's VASP about the recipient. Platform must provide these in the 200 OK response if approving. Note that this only includes fields which Grid does not already have from initial customer registration. + $ref: '#/components/schemas/IncomingPaymentWebhookData' type: type: string enum: @@ -8961,7 +9041,7 @@ components: type: string enum: - INVITATION.CLAIMED - CustomerKycWebhook: + CustomerWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' - type: object @@ -8969,7 +9049,7 @@ components: - data properties: data: - $ref: '#/components/schemas/IndividualCustomer' + $ref: '#/components/schemas/CustomerOneOf' type: type: string enum: @@ -8978,6 +9058,11 @@ components: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED InternalAccountStatusWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' diff --git a/openapi.yaml b/openapi.yaml index 938ee553..0842e59f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1623,6 +1623,32 @@ paths: application/json: schema: $ref: '#/components/schemas/Quote' + example: + id: Quote:019542f5-b3e7-1d02-0000-000000000006 + status: PENDING + createdAt: '2025-10-03T12:00:00Z' + expiresAt: '2025-10-03T12:05:00Z' + source: + sourceType: ACCOUNT + accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + sendingCurrency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + receivingCurrency: + code: EUR + name: Euro + symbol: € + decimals: 2 + totalSendingAmount: 10000 + totalReceivingAmount: 9200 + exchangeRate: 0.92 + feesIncluded: 10 + transactionId: Transaction:019542f5-b3e7-1d02-0000-000000000005 '400': description: Bad request - Missing or invalid parameters content: @@ -3517,11 +3543,11 @@ webhooks: application/json: schema: $ref: '#/components/schemas/Error409' - kyc-status: + customer-update: post: - summary: KYC customer status change + summary: Customer status change description: | - Webhook that is called when the KYC status of a customer is updated. + Webhook that is called when the status of a customer is updated, including KYC and KYB status changes. This endpoint should be implemented by clients of the Grid API. ### Authentication @@ -3533,20 +3559,7 @@ webhooks: 4. Verify the signature using the public key and the hash If the signature verification succeeds, the webhook is authentic. If not, it should be rejected. - - ### KYC/B Flow - This webhook is triggered when KYC/B has reached a decision on a customer. Generally most customers will finish KYC within a few minutes. Others might be rejected because of incorrect data passed in or may have been flagged for manual review. - The webhook will only trigger for final states. This will be APPROVED, REJECTED, EXPIRED, CANCELED, MANUALLY_APPROVED, MANUALLY_REJECTED. - - * APPROVED: The customer has been approved. - * REJECTED: The customer has been rejected after a KYC check. - * PENDING_REVIEW: KYC check is in progress. - * EXPIRED: KYC check has expired. This is generally because a customer did not submit all required information needed within a session. - * CANCELED: KYC check was canceled. - * MANUALLY_APPROVED: The customer was manually approved. - * MANUALLY_REJECTED: The customer was manually rejected. - * NOT_STARTED: KYC has not started on the customer. - operationId: kycStatusWebhook + operationId: customerStatusWebhook tags: - Webhooks security: @@ -3556,10 +3569,10 @@ webhooks: content: application/json: schema: - $ref: '#/components/schemas/CustomerKycWebhook' + $ref: '#/components/schemas/CustomerWebhook' examples: kycApprovedWebhook: - summary: When a customer KYC has been approved + summary: When an individual customer KYC has been approved value: id: Webhook:019542f5-b3e7-1d02-0000-000000000007 type: CUSTOMER.KYC_APPROVED @@ -3584,7 +3597,7 @@ webhooks: updatedAt: '2025-07-21T17:32:28Z' isDeleted: false kycRejectedWebhook: - summary: When a customer KYC has been rejected + summary: When an individual customer KYC has been rejected value: id: Webhook:019542f5-b3e7-1d02-0000-000000000008 type: CUSTOMER.KYC_REJECTED @@ -3601,6 +3614,54 @@ webhooks: createdAt: '2025-07-21T17:32:28Z' updatedAt: '2025-08-15T14:32:00Z' isDeleted: false + kybApprovedWebhook: + summary: When a business customer KYB has been approved + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: CUSTOMER.KYB_APPROVED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000003 + platformCustomerId: 7a2f9d4e1b8c3f5 + customerType: BUSINESS + umaAddress: $acme.corp@uma.domain.com + kybStatus: APPROVED + address: + line1: 456 Business Ave + city: New York + state: NY + postalCode: '10001' + country: US + businessInfo: + legalName: Acme Corporation + registrationNumber: '12345678' + taxId: 98-7654321 + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false + kybRejectedWebhook: + summary: When a business customer KYB has been rejected + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000010 + type: CUSTOMER.KYB_REJECTED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000004 + platformCustomerId: 3c8e5f2a9d1b7e4 + customerType: BUSINESS + umaAddress: $globex.inc@uma.domain.com + kybStatus: REJECTED + address: + line1: 789 Corporate Blvd + city: Chicago + state: IL + postalCode: '60601' + country: US + businessInfo: + legalName: Globex Inc + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false responses: '200': description: | @@ -4139,18 +4200,6 @@ components: - BUSINESS description: Whether the customer is an individual or a business entity example: INDIVIDUAL - KycStatus: - type: string - enum: - - APPROVED - - REJECTED - - PENDING_REVIEW - - EXPIRED - - CANCELED - - MANUALLY_APPROVED - - MANUALLY_REJECTED - description: The current KYC status of a customer - example: APPROVED Customer: type: object required: @@ -4169,8 +4218,6 @@ components: example: 9f84e0c2a72c4fa customerType: $ref: '#/components/schemas/CustomerType' - kycStatus: - $ref: '#/components/schemas/KycStatus' umaAddress: type: string description: Full UMA address (always present in responses, even if system-generated). This is an optional identifier to route payments to the customer. @@ -4192,6 +4239,18 @@ components: description: Whether the customer is marked as deleted example: false readOnly: true + KycStatus: + type: string + enum: + - APPROVED + - REJECTED + - PENDING_REVIEW + - EXPIRED + - CANCELED + - MANUALLY_APPROVED + - MANUALLY_REJECTED + description: The current KYC status of a customer + example: APPROVED Address: type: object required: @@ -4232,6 +4291,8 @@ components: type: string enum: - INDIVIDUAL + kycStatus: + $ref: '#/components/schemas/KycStatus' fullName: type: string description: Individual's full name @@ -4252,6 +4313,19 @@ components: allOf: - $ref: '#/components/schemas/Customer' - $ref: '#/components/schemas/IndividualCustomerFields' + KybStatus: + type: string + enum: + - AWAITING_SUBMISSION + - APPROVED + - REJECTED + - PENDING_REVIEW + - EXPIRED + - CANCELED + - MANUALLY_APPROVED + - MANUALLY_REJECTED + description: The current KYB status of a business customer + example: APPROVED BusinessInfoUpdate: type: object description: Additional information for business entities @@ -4331,6 +4405,8 @@ components: type: string enum: - BUSINESS + kybStatus: + $ref: '#/components/schemas/KybStatus' address: $ref: '#/components/schemas/Address' businessInfo: @@ -8824,6 +8900,11 @@ components: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED @@ -8836,7 +8917,6 @@ components: - timestamp - id - type - - data properties: id: type: string @@ -8850,9 +8930,17 @@ components: format: date-time description: ISO 8601 timestamp of when the webhook was sent example: '2025-08-15T14:32:00Z' - data: - type: object - description: The resource object. Contains the full resource as the corresponding GET endpoint would return it. + IncomingPaymentWebhookData: + title: Incoming Payment Webhook Data + allOf: + - $ref: '#/components/schemas/IncomingTransaction' + - type: object + properties: + requestedReceiverCustomerInfoFields: + type: array + items: + $ref: '#/components/schemas/CounterpartyFieldDefinition' + description: Information required by the sender's VASP about the recipient. Platform must provide these in the 200 OK response if approving. Note that this only includes fields which Grid does not already have from initial customer registration. IncomingPaymentWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' @@ -8861,15 +8949,7 @@ components: - data properties: data: - allOf: - - $ref: '#/components/schemas/IncomingTransaction' - - type: object - properties: - requestedReceiverCustomerInfoFields: - type: array - items: - $ref: '#/components/schemas/CounterpartyFieldDefinition' - description: Information required by the sender's VASP about the recipient. Platform must provide these in the 200 OK response if approving. Note that this only includes fields which Grid does not already have from initial customer registration. + $ref: '#/components/schemas/IncomingPaymentWebhookData' type: type: string enum: @@ -8961,7 +9041,7 @@ components: type: string enum: - INVITATION.CLAIMED - CustomerKycWebhook: + CustomerWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' - type: object @@ -8969,7 +9049,7 @@ components: - data properties: data: - $ref: '#/components/schemas/IndividualCustomer' + $ref: '#/components/schemas/CustomerOneOf' type: type: string enum: @@ -8978,6 +9058,11 @@ components: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED InternalAccountStatusWebhook: allOf: - $ref: '#/components/schemas/BaseWebhook' diff --git a/openapi/components/schemas/customers/BusinessCustomerFields.yaml b/openapi/components/schemas/customers/BusinessCustomerFields.yaml index 998bf832..65f3c2fa 100644 --- a/openapi/components/schemas/customers/BusinessCustomerFields.yaml +++ b/openapi/components/schemas/customers/BusinessCustomerFields.yaml @@ -6,6 +6,8 @@ properties: type: string enum: - BUSINESS + kybStatus: + $ref: ./KybStatus.yaml address: $ref: ../common/Address.yaml businessInfo: diff --git a/openapi/components/schemas/customers/Customer.yaml b/openapi/components/schemas/customers/Customer.yaml index 6f34b880..9d30da76 100644 --- a/openapi/components/schemas/customers/Customer.yaml +++ b/openapi/components/schemas/customers/Customer.yaml @@ -15,8 +15,6 @@ properties: example: 9f84e0c2a72c4fa customerType: $ref: ./CustomerType.yaml - kycStatus: - $ref: ./KycStatus.yaml umaAddress: type: string description: >- diff --git a/openapi/components/schemas/customers/IndividualCustomerFields.yaml b/openapi/components/schemas/customers/IndividualCustomerFields.yaml index 95616fef..45790ce2 100644 --- a/openapi/components/schemas/customers/IndividualCustomerFields.yaml +++ b/openapi/components/schemas/customers/IndividualCustomerFields.yaml @@ -6,6 +6,8 @@ properties: type: string enum: - INDIVIDUAL + kycStatus: + $ref: ./KycStatus.yaml fullName: type: string description: Individual's full name diff --git a/openapi/components/schemas/customers/KybStatus.yaml b/openapi/components/schemas/customers/KybStatus.yaml new file mode 100644 index 00000000..cec2061d --- /dev/null +++ b/openapi/components/schemas/customers/KybStatus.yaml @@ -0,0 +1,12 @@ +type: string +enum: + - AWAITING_SUBMISSION + - APPROVED + - REJECTED + - PENDING_REVIEW + - EXPIRED + - CANCELED + - MANUALLY_APPROVED + - MANUALLY_REJECTED +description: The current KYB status of a business customer +example: APPROVED diff --git a/openapi/components/schemas/transactions/IncomingPaymentWebhookData.yaml b/openapi/components/schemas/transactions/IncomingPaymentWebhookData.yaml new file mode 100644 index 00000000..b86aa81d --- /dev/null +++ b/openapi/components/schemas/transactions/IncomingPaymentWebhookData.yaml @@ -0,0 +1,14 @@ +title: Incoming Payment Webhook Data +allOf: + - $ref: ./IncomingTransaction.yaml + - type: object + properties: + requestedReceiverCustomerInfoFields: + type: array + items: + $ref: ../common/CounterpartyFieldDefinition.yaml + description: >- + Information required by the sender's VASP about the recipient. + Platform must provide these in the 200 OK response if approving. + Note that this only includes fields which Grid does not + already have from initial customer registration. diff --git a/openapi/components/schemas/webhooks/BaseWebhook.yaml b/openapi/components/schemas/webhooks/BaseWebhook.yaml index 17a3740f..c53025be 100644 --- a/openapi/components/schemas/webhooks/BaseWebhook.yaml +++ b/openapi/components/schemas/webhooks/BaseWebhook.yaml @@ -3,7 +3,6 @@ required: - timestamp - id - type - - data properties: id: type: string @@ -22,8 +21,3 @@ properties: description: >- ISO 8601 timestamp of when the webhook was sent example: '2025-08-15T14:32:00Z' - data: - type: object - description: >- - The resource object. Contains the full resource as the corresponding - GET endpoint would return it. diff --git a/openapi/components/schemas/webhooks/CustomerKycWebhook.yaml b/openapi/components/schemas/webhooks/CustomerWebhook.yaml similarity index 59% rename from openapi/components/schemas/webhooks/CustomerKycWebhook.yaml rename to openapi/components/schemas/webhooks/CustomerWebhook.yaml index 4b7c86cc..c8389f37 100644 --- a/openapi/components/schemas/webhooks/CustomerKycWebhook.yaml +++ b/openapi/components/schemas/webhooks/CustomerWebhook.yaml @@ -5,7 +5,7 @@ allOf: - data properties: data: - $ref: ../customers/IndividualCustomer.yaml + $ref: ../customers/CustomerOneOf.yaml type: type: string enum: @@ -14,3 +14,8 @@ allOf: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED diff --git a/openapi/components/schemas/webhooks/IncomingPaymentWebhook.yaml b/openapi/components/schemas/webhooks/IncomingPaymentWebhook.yaml index db3ef600..06b8247f 100644 --- a/openapi/components/schemas/webhooks/IncomingPaymentWebhook.yaml +++ b/openapi/components/schemas/webhooks/IncomingPaymentWebhook.yaml @@ -5,19 +5,7 @@ allOf: - data properties: data: - allOf: - - $ref: ../transactions/IncomingTransaction.yaml - - type: object - properties: - requestedReceiverCustomerInfoFields: - type: array - items: - $ref: ../common/CounterpartyFieldDefinition.yaml - description: >- - Information required by the sender's VASP about the recipient. - Platform must provide these in the 200 OK response if approving. - Note that this only includes fields which Grid does not - already have from initial customer registration. + $ref: ../transactions/IncomingPaymentWebhookData.yaml type: type: string enum: diff --git a/openapi/components/schemas/webhooks/WebhookType.yaml b/openapi/components/schemas/webhooks/WebhookType.yaml index f540da21..f18ae650 100644 --- a/openapi/components/schemas/webhooks/WebhookType.yaml +++ b/openapi/components/schemas/webhooks/WebhookType.yaml @@ -16,6 +16,11 @@ enum: - CUSTOMER.KYC_SUBMITTED - CUSTOMER.KYC_MANUALLY_APPROVED - CUSTOMER.KYC_MANUALLY_REJECTED + - CUSTOMER.KYB_APPROVED + - CUSTOMER.KYB_REJECTED + - CUSTOMER.KYB_SUBMITTED + - CUSTOMER.KYB_MANUALLY_APPROVED + - CUSTOMER.KYB_MANUALLY_REJECTED - INTERNAL_ACCOUNT.BALANCE_UPDATED - INVITATION.CLAIMED - BULK_UPLOAD.COMPLETED diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 289d60ec..6f033c9e 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -153,8 +153,8 @@ webhooks: $ref: webhooks/bulk-upload.yaml invitation-claimed: $ref: webhooks/invitation-claimed.yaml - kyc-status: - $ref: webhooks/customer-kyc.yaml + customer-update: + $ref: webhooks/customer-update.yaml internal-account-status: $ref: webhooks/internal-account-status.yaml security: diff --git a/openapi/paths/quotes/quotes.yaml b/openapi/paths/quotes/quotes.yaml index 8955a2b4..a3fc822e 100644 --- a/openapi/paths/quotes/quotes.yaml +++ b/openapi/paths/quotes/quotes.yaml @@ -93,6 +93,32 @@ post: application/json: schema: $ref: ../../components/schemas/quotes/Quote.yaml + example: + id: Quote:019542f5-b3e7-1d02-0000-000000000006 + status: PENDING + createdAt: '2025-10-03T12:00:00Z' + expiresAt: '2025-10-03T12:05:00Z' + source: + sourceType: ACCOUNT + accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + sendingCurrency: + code: USD + name: United States Dollar + symbol: $ + decimals: 2 + receivingCurrency: + code: EUR + name: Euro + symbol: € + decimals: 2 + totalSendingAmount: 10000 + totalReceivingAmount: 9200 + exchangeRate: 0.92 + feesIncluded: 10 + transactionId: Transaction:019542f5-b3e7-1d02-0000-000000000005 '400': description: Bad request - Missing or invalid parameters content: diff --git a/openapi/webhooks/customer-kyc.yaml b/openapi/webhooks/customer-update.yaml similarity index 56% rename from openapi/webhooks/customer-kyc.yaml rename to openapi/webhooks/customer-update.yaml index 1b70e7b0..097684e9 100644 --- a/openapi/webhooks/customer-kyc.yaml +++ b/openapi/webhooks/customer-update.yaml @@ -1,7 +1,7 @@ post: - summary: KYC customer status change + summary: Customer status change description: > - Webhook that is called when the KYC status of a customer is updated. + Webhook that is called when the status of a customer is updated, including KYC and KYB status changes. This endpoint should be implemented by clients of the Grid API. @@ -25,23 +25,7 @@ post: If the signature verification succeeds, the webhook is authentic. If not, it should be rejected. - - ### KYC/B Flow - - This webhook is triggered when KYC/B has reached a decision on a customer. Generally most customers will finish KYC within a few minutes. - Others might be rejected because of incorrect data passed in or may have been flagged for manual review. - - The webhook will only trigger for final states. This will be APPROVED, REJECTED, EXPIRED, CANCELED, MANUALLY_APPROVED, MANUALLY_REJECTED. - - * APPROVED: The customer has been approved. - * REJECTED: The customer has been rejected after a KYC check. - * PENDING_REVIEW: KYC check is in progress. - * EXPIRED: KYC check has expired. This is generally because a customer did not submit all required information needed within a session. - * CANCELED: KYC check was canceled. - * MANUALLY_APPROVED: The customer was manually approved. - * MANUALLY_REJECTED: The customer was manually rejected. - * NOT_STARTED: KYC has not started on the customer. - operationId: kycStatusWebhook + operationId: customerStatusWebhook tags: - Webhooks security: @@ -51,10 +35,10 @@ post: content: application/json: schema: - $ref: ../components/schemas/webhooks/CustomerKycWebhook.yaml + $ref: ../components/schemas/webhooks/CustomerWebhook.yaml examples: kycApprovedWebhook: - summary: When a customer KYC has been approved + summary: When an individual customer KYC has been approved value: id: Webhook:019542f5-b3e7-1d02-0000-000000000007 type: CUSTOMER.KYC_APPROVED @@ -79,7 +63,7 @@ post: updatedAt: '2025-07-21T17:32:28Z' isDeleted: false kycRejectedWebhook: - summary: When a customer KYC has been rejected + summary: When an individual customer KYC has been rejected value: id: Webhook:019542f5-b3e7-1d02-0000-000000000008 type: CUSTOMER.KYC_REJECTED @@ -96,6 +80,54 @@ post: createdAt: '2025-07-21T17:32:28Z' updatedAt: '2025-08-15T14:32:00Z' isDeleted: false + kybApprovedWebhook: + summary: When a business customer KYB has been approved + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000009 + type: CUSTOMER.KYB_APPROVED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000003 + platformCustomerId: 7a2f9d4e1b8c3f5 + customerType: BUSINESS + umaAddress: $acme.corp@uma.domain.com + kybStatus: APPROVED + address: + line1: 456 Business Ave + city: New York + state: NY + postalCode: '10001' + country: US + businessInfo: + legalName: Acme Corporation + registrationNumber: '12345678' + taxId: '98-7654321' + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false + kybRejectedWebhook: + summary: When a business customer KYB has been rejected + value: + id: Webhook:019542f5-b3e7-1d02-0000-000000000010 + type: CUSTOMER.KYB_REJECTED + timestamp: '2025-08-15T14:32:00Z' + data: + id: Customer:019542f5-b3e7-1d02-0000-000000000004 + platformCustomerId: 3c8e5f2a9d1b7e4 + customerType: BUSINESS + umaAddress: $globex.inc@uma.domain.com + kybStatus: REJECTED + address: + line1: 789 Corporate Blvd + city: Chicago + state: IL + postalCode: '60601' + country: US + businessInfo: + legalName: Globex Inc + createdAt: '2025-07-21T17:32:28Z' + updatedAt: '2025-08-15T14:32:00Z' + isDeleted: false responses: '200': description: >