squarefi-bff-api-module 1.36.84 → 1.36.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,8 @@ export declare const counterparties: {
9
9
  destinations: {
10
10
  getAll: ({ wallet_id, ...params }: API.Counterparties.Destination.List.Request) => Promise<API.Counterparties.Destination.List.Response>;
11
11
  getById: ({ counterparty_destination_id, }: API.Counterparties.Destination.Detail.Request) => Promise<API.Counterparties.Destination.Detail.Response>;
12
- create: ({ wallet_id: _wallet_id, external_banking_data, external_crypto_data, internal_data, ...rest }: API.Counterparties.Destination.Create.Request) => Promise<API.Counterparties.Destination.Create.Response>;
12
+ create: (request: API.Counterparties.Destination.Create.Request) => Promise<API.Counterparties.Destination.Create.Response>;
13
+ validate: (request: API.Counterparties.Destination.Validate.Request) => Promise<API.Counterparties.Destination.Validate.Response>;
13
14
  update: ({ counterparty_destination_id, wallet_id: _wallet_id, counterparty_account_id: _counterparty_account_id, ...data }: API.Counterparties.Destination.Update.Request) => Promise<API.Counterparties.Destination.Update.Response>;
14
15
  delete: ({ counterparty_destination_id, request_id, }: API.Counterparties.Destination.Delete.Request) => Promise<void>;
15
16
  internalTransfer: ({ counterparty_destination_id, }: API.Counterparties.Destination.InternalTransfer.Request) => Promise<API.Counterparties.Destination.InternalTransfer.Response>;
@@ -16,8 +16,20 @@ const mapDestination = (destination) => {
16
16
  if (destination.type === 'INTERNAL') {
17
17
  return { ...common, internal_data: destination.internal_data };
18
18
  }
19
- return { ...common, external_banking_data: destination.banking_data };
19
+ return {
20
+ ...common,
21
+ external_banking_data: destination.banking_data,
22
+ ...(destination.validation_issues ? { validation_issues: destination.validation_issues } : {}),
23
+ };
20
24
  };
25
+ // Тело create/validate: наружу external_* контракт, на провод — ключи фронт-модуля. wallet_id бэкенду
26
+ // не нужен (кошелёк берётся из счёта контрагента) и не отправляется.
27
+ const toDestinationBody = ({ wallet_id: _wallet_id, external_banking_data, external_crypto_data, internal_data, ...rest }) => ({
28
+ ...rest,
29
+ ...(external_banking_data ? { banking_data: external_banking_data } : {}),
30
+ ...(external_crypto_data ? { crypto_data: external_crypto_data } : {}),
31
+ ...(internal_data ? { internal_data } : {}),
32
+ });
21
33
  export const counterparties = {
22
34
  getAll: async ({ wallet_id, ...params }) => {
23
35
  const res = await apiClientV1Frontend.getRequest(`/frontend/counterparty/accounts/wallet/${wallet_id}`, { params });
@@ -65,16 +77,18 @@ export const counterparties = {
65
77
  const res = await apiClientV1Frontend.getRequest(`/frontend/counterparty/destinations/${counterparty_destination_id}`);
66
78
  return mapDestination(res.data.destination);
67
79
  },
68
- create: async ({ wallet_id: _wallet_id, external_banking_data, external_crypto_data, internal_data, ...rest }) => {
69
- const data = {
70
- ...rest,
71
- ...(external_banking_data ? { banking_data: external_banking_data } : {}),
72
- ...(external_crypto_data ? { crypto_data: external_crypto_data } : {}),
73
- ...(internal_data ? { internal_data } : {}),
74
- };
80
+ create: async (request) => {
81
+ const data = toDestinationBody(request);
75
82
  const res = await apiClientV1Frontend.postRequest(`/frontend/counterparty/destinations`, { data });
76
83
  return mapDestination(res.data.destination);
77
84
  },
85
+ // Пробный прогон create: те же проверки реквизитов, ничего не сохраняет. Правила живут
86
+ // только на бэкенде — формы спрашивают этот вызов вместо собственных проверок формата.
87
+ validate: async (request) => {
88
+ const data = toDestinationBody(request);
89
+ const res = await apiClientV1Frontend.postRequest(`/frontend/counterparty/destinations/validate`, { data });
90
+ return res.data;
91
+ },
78
92
  update: async ({ counterparty_destination_id, wallet_id: _wallet_id, counterparty_account_id: _counterparty_account_id, ...data }) => {
79
93
  const res = await apiClientV1Frontend.patchRequest(`/frontend/counterparty/destinations/${counterparty_destination_id}`, { data });
80
94
  return mapDestination(res.data.destination);
@@ -1226,7 +1226,8 @@ export interface paths {
1226
1226
  * Matching is by full code — prefix search is not supported, so `data`
1227
1227
  * carries at most one element today. A well-formed code that matches no
1228
1228
  * bank is `200` with an empty `data`, not a 404. Banks that do not accept
1229
- * the selected method also resolve to an empty `data`.
1229
+ * the selected method also resolve to an empty `data` — for `sepa`, that
1230
+ * includes a bank outside the SEPA zone.
1230
1231
  *
1231
1232
  * **Authentication**: Bearer token + x-tenant-id header
1232
1233
  *
@@ -1958,6 +1959,183 @@ export interface paths {
1958
1959
  patch?: never;
1959
1960
  trace?: never;
1960
1961
  };
1962
+ "/frontend/counterparty/destinations": {
1963
+ parameters: {
1964
+ query?: never;
1965
+ header?: never;
1966
+ path?: never;
1967
+ cookie?: never;
1968
+ };
1969
+ get?: never;
1970
+ put?: never;
1971
+ /**
1972
+ * Create destination
1973
+ * @description counterparty_account_id in body. Caller must be owner or admin of the account's wallet and the wallet's KYC must be APPROVED; other members receive 403.
1974
+ *
1975
+ * **Banking types**: banking_data required. `banking_data.address` (the bank address) is mandatory; `banking_data.beneficiary_address` (the recipient's own postal address, same shape) is optional — when present it must be complete (city, country_id, postcode, street1; state_id on US rails), is never overwritten by bank-directory enrichment, is exempt from the bank-country check, and payouts use it in place of the bank address.
1976
+ * **Crypto types**: crypto_data required
1977
+ * **Internal type**: internal_data required (target wallet on the same platform)
1978
+ *
1979
+ */
1980
+ post: {
1981
+ parameters: {
1982
+ query?: never;
1983
+ header?: never;
1984
+ path?: never;
1985
+ cookie?: never;
1986
+ };
1987
+ requestBody: {
1988
+ content: {
1989
+ "application/json": {
1990
+ /** Format: uuid */
1991
+ counterparty_account_id: string;
1992
+ /** @enum {string} */
1993
+ type: "ACH" | "RTP" | "SWIFT" | "SEPA" | "CRYPTO_EXTERNAL" | "CRYPTO_INTERNAL" | "CHAPS" | "FPS" | "FEDWIRE" | "INTERNAL";
1994
+ nickname?: string;
1995
+ banking_data?: Record<string, never>;
1996
+ crypto_data?: Record<string, never>;
1997
+ /** @description Required for type INTERNAL — points at the receiver wallet. An account holds one INTERNAL destination per wallet; if it already has an active one to this wallet, that destination is returned instead of a new one. */
1998
+ internal_data?: {
1999
+ /**
2000
+ * Format: uuid
2001
+ * @description Target (receiver) wallet uuid on the same platform.
2002
+ */
2003
+ wallet_id: string;
2004
+ /** @description Optional, reserved for future use. */
2005
+ description?: string;
2006
+ };
2007
+ };
2008
+ };
2009
+ };
2010
+ responses: {
2011
+ /** @description Created */
2012
+ 201: {
2013
+ headers: {
2014
+ [name: string]: unknown;
2015
+ };
2016
+ content: {
2017
+ "application/json": {
2018
+ /** @example true */
2019
+ success: boolean;
2020
+ data: {
2021
+ destination: components["schemas"]["CounterpartyDestination"];
2022
+ /** @example Destination created successfully */
2023
+ message: string;
2024
+ };
2025
+ };
2026
+ };
2027
+ };
2028
+ /** @description Validation error: type-specific payload missing or invalid, target wallet inactive, or the address country contradicts the bank code country (`BANK_COUNTRY_MISMATCH`).
2029
+ *
2030
+ * Bank details are checked per payment method — IBAN (country, length, account format, check digits), SWIFT/BIC, ABA routing number, US/UK account number, sort code, IBAN inside the SEPA zone on SEPA. Every problem is listed in `error.details.issues` (`field`, `code`, `message`, optional `country` / `detected`), so a form can mark each field; `POST /frontend/counterparty/destinations/validate` returns the same list without saving.
2031
+ * */
2032
+ 400: {
2033
+ headers: {
2034
+ [name: string]: unknown;
2035
+ };
2036
+ content: {
2037
+ "application/json": components["schemas"]["ErrorResponse"];
2038
+ };
2039
+ };
2040
+ /** @description Access denied, or (Clerk tenants) the second-factor verification is
2041
+ * stale — `TWO_FACTOR_REVERIFICATION_REQUIRED`: re-verify and retry.
2042
+ * */
2043
+ 403: {
2044
+ headers: {
2045
+ [name: string]: unknown;
2046
+ };
2047
+ content: {
2048
+ "application/json": components["schemas"]["ErrorResponse"];
2049
+ };
2050
+ };
2051
+ /** @description Account not found */
2052
+ 404: {
2053
+ headers: {
2054
+ [name: string]: unknown;
2055
+ };
2056
+ content: {
2057
+ "application/json": components["schemas"]["ErrorResponse"];
2058
+ };
2059
+ };
2060
+ };
2061
+ };
2062
+ delete?: never;
2063
+ options?: never;
2064
+ head?: never;
2065
+ patch?: never;
2066
+ trace?: never;
2067
+ };
2068
+ "/frontend/counterparty/destinations/validate": {
2069
+ parameters: {
2070
+ query?: never;
2071
+ header?: never;
2072
+ path?: never;
2073
+ cookie?: never;
2074
+ };
2075
+ get?: never;
2076
+ put?: never;
2077
+ /**
2078
+ * Validate destination details without saving
2079
+ * @description Dry run of `POST /frontend/counterparty/destinations`: the same body, the same checks —
2080
+ * bank details per payment method, address completeness, location reference data, the
2081
+ * bank-country check — and nothing is saved. Answers `200` whether or not the details are
2082
+ * valid; `valid: false` comes with every problem in `issues`. A form calls it as bank fields
2083
+ * are left and before submitting, and shows each issue's `message` under its `field`.
2084
+ *
2085
+ * No counterparty account is needed and no second-factor step-up is asked. Without an account it
2086
+ * cannot tell whether an INTERNAL target wallet is active — creation still checks that. Rate limited
2087
+ * to 60 requests per minute per user.
2088
+ *
2089
+ */
2090
+ post: {
2091
+ parameters: {
2092
+ query?: never;
2093
+ header?: never;
2094
+ path?: never;
2095
+ cookie?: never;
2096
+ };
2097
+ requestBody: {
2098
+ content: {
2099
+ "application/json": {
2100
+ /** @enum {string} */
2101
+ type: "ACH" | "RTP" | "SWIFT" | "SEPA" | "CRYPTO_EXTERNAL" | "CRYPTO_INTERNAL" | "CHAPS" | "FPS" | "FEDWIRE" | "INTERNAL";
2102
+ banking_data?: Record<string, never>;
2103
+ crypto_data?: Record<string, never>;
2104
+ internal_data?: Record<string, never>;
2105
+ };
2106
+ };
2107
+ };
2108
+ responses: {
2109
+ /** @description Validation result */
2110
+ 200: {
2111
+ headers: {
2112
+ [name: string]: unknown;
2113
+ };
2114
+ content: {
2115
+ "application/json": {
2116
+ /** @example true */
2117
+ success: boolean;
2118
+ data: components["schemas"]["DestinationValidationResult"];
2119
+ };
2120
+ };
2121
+ };
2122
+ /** @description Too many validation requests */
2123
+ 429: {
2124
+ headers: {
2125
+ [name: string]: unknown;
2126
+ };
2127
+ content: {
2128
+ "application/json": components["schemas"]["ErrorResponse"];
2129
+ };
2130
+ };
2131
+ };
2132
+ };
2133
+ delete?: never;
2134
+ options?: never;
2135
+ head?: never;
2136
+ patch?: never;
2137
+ trace?: never;
2138
+ };
1961
2139
  "/frontend/crypto_wallets/wallet/{wallet_id}": {
1962
2140
  parameters: {
1963
2141
  query?: never;
@@ -15950,9 +16128,38 @@ export interface components {
15950
16128
  banking_data?: components["schemas"]["CounterpartyBankingData"] | null;
15951
16129
  crypto_data?: components["schemas"]["CounterpartyCryptoData"] | null;
15952
16130
  internal_data?: components["schemas"]["CounterpartyInternalData"] | null;
16131
+ /** @description Banking destinations only: problems that make the stored bank details unpayable (an IBAN that fails its checks, an IBAN outside SEPA on a SEPA destination, a routing number that fails the ABA check). Non-empty means withdrawals to this destination are refused with `DESTINATION_INVALID` — details cannot be edited, so add a new destination. Empty for valid banking destinations; absent for crypto and internal ones. */
16132
+ validation_issues?: components["schemas"]["DestinationValidationIssue"][];
15953
16133
  /** @description Embedded on the list and get-by-id reads; absent on create/update. */
15954
16134
  counterparty_account?: components["schemas"]["CounterpartyAccountRef"] | null;
15955
16135
  };
16136
+ /** @description One problem with a destination payload. `field` is the request path of the offending value (`iban`, `routing_number`, `address.city`…); `message` is ready to show under that field. */
16137
+ DestinationValidationIssue: {
16138
+ /** @example iban */
16139
+ field: string;
16140
+ /**
16141
+ * @description Machine-readable reason. Bank details: `REQUIRED`, `IBAN_WRONG_FORMAT`, `IBAN_INVALID_CHARACTERS`, `IBAN_COUNTRY_NOT_SUPPORTED`, `IBAN_WRONG_LENGTH`, `IBAN_WRONG_BBAN_FORMAT`, `IBAN_WRONG_CHECKSUM`, `IBAN_WRONG_NATIONAL_CHECKSUM`, `IBAN_QR_NOT_ALLOWED`, `IBAN_NOT_SEPA`, `IBAN_BIC_COUNTRY_MISMATCH`, `BIC_WRONG_FORMAT`, `BIC_UNKNOWN_COUNTRY`, `BIC_TEST_CODE`, `ROUTING_NUMBER_INVALID`, `ACCOUNT_NUMBER_INVALID`, `SORT_CODE_INVALID`, `WRONG_IDENTIFIER_TYPE`, `INVALID_VALUE`; reference data: `BANK_COUNTRY_MISMATCH`, `VALIDATION_ERROR`; dry run only: `INVALID_TYPE`. New codes may be added — show `message` for an unknown one.
16142
+ * @example IBAN_NOT_SEPA
16143
+ */
16144
+ code: string;
16145
+ /** @example IBAN country AE is outside the SEPA zone — SEPA transfers cannot reach it */
16146
+ message: string;
16147
+ /**
16148
+ * @description ISO 3166-1 alpha-2 country the problem is about, when there is one
16149
+ * @example AE
16150
+ */
16151
+ country?: string;
16152
+ /**
16153
+ * @description For `WRONG_IDENTIFIER_TYPE`: what the value looks like (an IBAN typed into a US account-number field…)
16154
+ * @enum {string}
16155
+ */
16156
+ detected?: "IBAN" | "BIC" | "ROUTING_NUMBER";
16157
+ };
16158
+ DestinationValidationResult: {
16159
+ /** @description True when creating the destination with this payload would pass every check */
16160
+ valid: boolean;
16161
+ issues: components["schemas"]["DestinationValidationIssue"][];
16162
+ };
15956
16163
  /** @description Whether an instant internal transfer is available for a counterparty destination. Two states: available (available=true, target_wallet_id set) and not available (available=false, target_wallet_id=null). Any recipient that cannot receive an instant internal transfer is uniformly reported as not available — the check does not disclose the reason. */
15957
16164
  InternalTransferAvailability: {
15958
16165
  /** @description True when the recipient is an on-platform wallet that can currently receive an instant internal transfer. */
@@ -481,6 +481,7 @@ export declare namespace API {
481
481
  type CryptoDestinationType = Extract<CounterpartyDestinationType, 'CRYPTO_EXTERNAL'> | Extract<CounterpartyDestinationType, 'CRYPTO_INTERNAL'>;
482
482
  type InternalDestinationType = Extract<CounterpartyDestinationType, 'INTERNAL'>;
483
483
  type DestinationType = BankingDestinationType | CryptoDestinationType | InternalDestinationType;
484
+ type ValidationIssue = componentsV1Frontend['schemas']['DestinationValidationIssue'];
484
485
  namespace List {
485
486
  interface DestinationListItemCommonFields {
486
487
  id: string;
@@ -496,18 +497,21 @@ export declare namespace API {
496
497
  external_banking_data: DestinationListItemExternalBankingData;
497
498
  external_crypto_data?: never;
498
499
  internal_data?: never;
500
+ validation_issues?: ValidationIssue[];
499
501
  }
500
502
  interface DestinationListItemWithExternalCryptoData extends DestinationListItemCommonFields {
501
503
  type: CryptoDestinationType;
502
504
  external_banking_data?: never;
503
505
  external_crypto_data: DestinationListItemExternalCryptoData;
504
506
  internal_data?: never;
507
+ validation_issues?: never;
505
508
  }
506
509
  interface DestinationListItemWithInternalData extends DestinationListItemCommonFields {
507
510
  type: InternalDestinationType;
508
511
  external_banking_data?: never;
509
512
  external_crypto_data?: never;
510
513
  internal_data: DestinationInternalData;
514
+ validation_issues?: never;
511
515
  }
512
516
  type CounterpartyDestinationListItem = DestinationListItemWithExternalBankingData | DestinationListItemWithExternalCryptoData | DestinationListItemWithInternalData;
513
517
  type Request = pathsV1Frontend['/frontend/counterparty/destinations/wallet/{wallet_id}']['get']['parameters']['path'] & NonNullable<pathsV1Frontend['/frontend/counterparty/destinations/wallet/{wallet_id}']['get']['parameters']['query']>;
@@ -550,6 +554,10 @@ export declare namespace API {
550
554
  }
551
555
  type Response = Detail.DestinationDetailItem;
552
556
  }
557
+ namespace Validate {
558
+ type Request = Omit<Create.Request, 'counterparty_account_id' | 'nickname'>;
559
+ type Response = componentsV1Frontend['schemas']['DestinationValidationResult'];
560
+ }
553
561
  namespace Delete {
554
562
  type Request = {
555
563
  counterparty_destination_id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squarefi-bff-api-module",
3
- "version": "1.36.84",
3
+ "version": "1.36.85",
4
4
  "description": "Squarefi BFF API client module",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",