@spritz-finance/api-client 0.4.26 → 0.4.28

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.
package/README.md CHANGED
@@ -1,178 +1,125 @@
1
1
  # @spritz-finance/api-client
2
2
 
3
- A Typescript library for interacting with the Spritz Finance API
3
+ TypeScript client for the Spritz Finance API — convert crypto to fiat payments.
4
4
 
5
5
  [![NPM](https://img.shields.io/npm/v/@spritz-finance/api-client.svg)](https://www.npmjs.com/package/@spritz-finance/api-client)
6
6
 
7
7
  ## Installation
8
8
 
9
- ### Using npm
10
-
11
9
  ```bash
12
- npm install --save @spritz-finance/api-client
13
- ```
14
-
15
- ### Using yarn
16
-
17
- ```bash
18
- yarn add @spritz-finance/api-client
10
+ npm install @spritz-finance/api-client
11
+ # or
12
+ yarn add @spritz-finance/api-client
19
13
  ```
20
14
 
21
15
  ## Quick Start
22
16
 
23
- Get started with Spritz in minutes:
24
-
25
17
  ```typescript
26
18
  import {
27
- SpritzApiClient,
28
- Environment,
29
- PaymentNetwork,
30
- BankAccountType,
31
- BankAccountSubType,
32
- DebitCardNetwork,
33
- AmountMode,
19
+ SpritzApiClient,
20
+ Environment,
21
+ PaymentNetwork,
22
+ BankAccountType,
23
+ BankAccountSubType,
34
24
  } from '@spritz-finance/api-client'
35
25
 
36
- // Initialize the client with your integration key
26
+ // Initialize with your integration key
37
27
  const client = SpritzApiClient.initialize({
38
- environment: Environment.Sandbox,
39
- integrationKey: 'YOUR_INTEGRATION_KEY_HERE',
40
- })
41
-
42
- // Create a user
43
- const user = await client.user.create({
44
- email: 'user@example.com',
28
+ environment: Environment.Sandbox,
29
+ integrationKey: 'YOUR_INTEGRATION_KEY_HERE',
45
30
  })
46
31
 
47
- // Set the user's API key
32
+ // Create a user and set their API key
33
+ const user = await client.user.create({ email: 'user@example.com' })
48
34
  client.setApiKey(user.apiKey)
49
35
 
50
36
  // Add a bank account
51
37
  const bankAccount = await client.bankAccount.create(BankAccountType.USBankAccount, {
52
- accountNumber: '123456789',
53
- routingNumber: '987654321',
54
- name: 'My Checking Account',
55
- ownedByUser: true,
56
- subType: BankAccountSubType.Checking,
38
+ accountNumber: '123456789',
39
+ routingNumber: '987654321',
40
+ name: 'My Checking Account',
41
+ ownedByUser: true,
42
+ subType: BankAccountSubType.Checking,
57
43
  })
58
44
 
59
45
  // Create a payment request
60
46
  const paymentRequest = await client.paymentRequest.create({
61
- amount: 100,
62
- accountId: bankAccount.id,
63
- network: PaymentNetwork.Ethereum,
47
+ amount: 100,
48
+ accountId: bankAccount.id,
49
+ network: PaymentNetwork.Ethereum,
64
50
  })
65
51
 
66
- // Get transaction data for blockchain payment
52
+ // Get transaction data for the blockchain payment
67
53
  const transactionData = await client.paymentRequest.getWeb3PaymentParams({
68
- paymentRequest,
69
- paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC on mainnet
54
+ paymentRequest,
55
+ paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
70
56
  })
71
57
 
72
- // Use transactionData to execute blockchain transaction in your app
58
+ // Execute the blockchain transaction from the user's wallet
73
59
  ```
74
60
 
75
- ## Table of contents
76
-
77
- - [Quick Start](#quick-start)
78
- - [Installation](#installation)
79
- - [API Overview](#api-overview)
80
- - [Creating a user](#creating-a-user)
81
- - [Capabilities of the API Key](#capabilities-of-the-api-key)
82
- - [Usage](#usage)
83
- - [User Management](#user-management)
84
- - [Creating a user](#creating-a-user-1)
85
- - [Setting the User API Key](#setting-the-user-api-key)
86
- - [Reauthorizing a user](#reauthorizing-a-user)
87
- - [Basic User Data](#basic-user-data)
88
- - [User Verification](#user-verification)
89
- - [Payment Flow](#payment-flow)
90
- - [Basic payment flow](#basic-payment-flow)
91
- - [Note on Issuing the Blockchain Transaction](#note-on-issuing-the-blockchain-transaction)
92
- - [Example](#example)
61
+ ## Table of Contents
62
+
63
+ - [Authentication](#authentication)
64
+ - [Users](#users)
65
+ - [Creating a User](#creating-a-user)
66
+ - [Reauthorization](#reauthorization)
67
+ - [User Data](#user-data)
68
+ - [Identity Verification](#identity-verification)
93
69
  - [Accounts](#accounts)
94
- - [Account Types](#account-types)
95
- - [Commonalities & Differences](#commonalities---differences)
96
- - [Bank Accounts](#bank-accounts)
97
- - [Debit Cards](#debit-cards)
98
- - [Bills](#bills)
99
- - [Virtual Card](#virtual-card)
100
- - [Address Book](#address-book)
101
- - [Account Management](#account-management)
102
- - [Renaming accounts](#renaming-accounts)
103
- - [Deleting accounts](#deleting-accounts)
104
- - [Bill Institutions](#bill-institutions)
105
- - [Fetching popular bill institutions](#fetching-popular-bill-institutions)
106
- - [Searching for bill institutions by name](#searching-for-bill-institutions-by-name)
107
- - [Payment Requests](#payment-requests)
108
- - [Create a payment request](#create-a-payment-request)
109
- - [Fulfil a payment request (EVM transactions)](#fulfil-a-payment-request--evm-transactions-)
110
- - [Fulfil a payment request (Solana transactions)](#fulfil-a-payment-request--solana-transactions-)
111
- - [Transaction fees](#transaction-fees)
112
- - [Payments](#payments)
113
- - [Retrieve the payment for a payment request](#retrieve-the-payment-for-a-payment-request)
114
- - [Retrieve all payments for an account](#retrieve-all-payments-for-an-account)
115
- - [Get payment limits for an account](#get-payment-limits-for-an-account)
116
- - [Onramp Payments](#onramp-payments)
117
- - [Create an onramp payment](#create-onramp-payment)
118
- - [Retrieve all onramp payments for an account](#retrieve-all-onramp-payments-for-an-account)
70
+ - [Bank Accounts](#bank-accounts)
71
+ - [Debit Cards](#debit-cards)
72
+ - [Bills](#bills)
73
+ - [Virtual Cards](#virtual-cards)
74
+ - [Address Book](#address-book)
75
+ - [Renaming Accounts](#renaming-accounts)
76
+ - [Deleting Accounts](#deleting-accounts)
77
+ - [Payments (Off-ramp)](#payments-off-ramp)
78
+ - [Payment Flow](#payment-flow)
79
+ - [Creating a Payment Request](#creating-a-payment-request)
80
+ - [Fulfilling a Payment — EVM](#fulfilling-a-payment--evm)
81
+ - [Fulfilling a Payment — Solana](#fulfilling-a-payment--solana)
82
+ - [Transaction Fees](#transaction-fees)
83
+ - [Retrieving Payments](#retrieving-payments)
84
+ - [Payment Limits](#payment-limits)
85
+ - [On-ramp](#on-ramp)
86
+ - [Prerequisites](#prerequisites)
87
+ - [Checking User Access](#checking-user-access)
88
+ - [Activation Steps](#activation-steps)
89
+ - [Virtual Accounts](#virtual-accounts)
90
+ - [Supported Tokens](#supported-tokens)
119
91
  - [Webhooks](#webhooks)
120
- - [Supported webhook events](#supported-webhook-events)
121
- - [Setting up webhooks](#setting-up-webhooks)
122
- - [On-ramp Setup Guide](#on-ramp-setup-guide)
123
- - [Prerequisites](#prerequisites)
124
- - [Checking User Access Capabilities](#checking-user-access-capabilities)
125
- - [Step-by-Step On-ramp Activation](#step-by-step-on-ramp-activation)
126
- - [Creating Virtual Accounts](#creating-virtual-accounts)
127
- - [Listing Virtual Accounts](#listing-virtual-accounts)
128
- - [Supported Token Matrix](#supported-token-matrix)
129
- - [Complete Example](#complete-example)
130
-
131
- ## API Overview
92
+ - [Events](#events)
93
+ - [Setup](#setup)
94
+ - [Management](#management)
95
+ - [Security and Signing](#security-and-signing)
132
96
 
133
- **Purpose**: As an integrator, this guide will assist you in creating users and performing user-specific operations on the Spritz platform using the provided API key.
97
+ ## Authentication
134
98
 
135
- ### Creating a user
99
+ Spritz uses two levels of authentication:
136
100
 
137
- When you create a user using your integration key:
138
-
139
- - You will receive an `API key` specific to that user.
140
- - This enables you to interact with the Spritz platform on the user's behalf.
141
-
142
- ### Capabilities of the API Key
143
-
144
- Using the user-specific API key, you can:
145
-
146
- 1. **Identity Verification**: Guide a user through the identity verification process.
147
- 2. **Account Addition**:
148
- - Add Bills for the user.
149
- - Register Bank accounts.
150
- - Issue Virtual cards.
151
- 3. **Payment Requests**: Initiate payment requests to the aforementioned accounts.
152
- 4. **Blockchain Transactions**: Issue blockchain-based transactions to fulfill the payment requests.
153
- 5. **Payment Status**: Query the status of payments directed to the user's accounts.
154
-
155
- ## Usage
156
-
157
- Your integration key is provided by Spritz and must always be provided.
158
- The api key is specific to each user,
159
- and is returned once the user is created. Leave the api key blank if you haven't created the user yet.
101
+ - **Integration key** identifies your application. Provided by Spritz.
102
+ - **User API key** — scoped to a single user. Returned when you create a user.
160
103
 
161
104
  ```typescript
162
105
  import { SpritzApiClient, Environment } from '@spritz-finance/api-client'
163
106
 
164
107
  const client = SpritzApiClient.initialize({
165
- environment: Environment.Sandbox,
166
- apiKey: 'YOUR_USER_API_KEY_HERE',
167
- integrationKey: 'YOUR_INTEGRATION_KEY_HERE',
108
+ environment: Environment.Sandbox,
109
+ integrationKey: 'YOUR_INTEGRATION_KEY_HERE',
110
+ apiKey: 'YOUR_USER_API_KEY_HERE', // omit if no user exists yet
168
111
  })
169
112
  ```
170
113
 
171
- ## User Management
114
+ After creating a user, set their API key on the client:
172
115
 
173
- ### Creating a user
116
+ ```typescript
117
+ client.setApiKey(user.apiKey)
118
+ ```
119
+
120
+ ## Users
174
121
 
175
- To create a new Spritz user, all you need is the user's email address. Note that trying to create a user with an email that already exists in the Spritz platform will throw an error.
122
+ ### Creating a User
176
123
 
177
124
  ```typescript
178
125
  const user = await client.user.create({
@@ -180,504 +127,339 @@ const user = await client.user.create({
180
127
  })
181
128
 
182
129
  // Response
183
- user = {
184
- email: "bilbo@shiremail.net"
185
- userId: "62d17d3b377dab6c1342136e",
186
- apiKey: "ak_ZTBGDcjfdTg3NmYtZDJlZC00ZjYyLThlMDMtZmYwNDJiZDRlMWZm"
130
+ {
131
+ email: 'bilbo@shiremail.net',
132
+ userId: '62d17d3b377dab6c1342136e',
133
+ apiKey: 'ak_ZTBGDcjfdTg3NmYtZDJlZC00ZjYyLThlMDMtZmYwNDJiZDRlMWZm',
187
134
  }
188
135
  ```
189
136
 
190
- ### Setting the User API Key
137
+ Creating a user with an email that already exists will throw an error.
191
138
 
192
- After creating a user, you can easily set the user's API key onto your initialized client using the provided method:
139
+ ### Reauthorization
193
140
 
194
- ```typescript
195
- client.setApiKey(user.apiKey)
196
- ```
197
-
198
- Now you're ready to issue requests on behalf of the user.
199
-
200
- ### Reauthorizing a user
201
-
202
- There is a scenrio where you may need to get access to a users API key again. This can happen if you are trying to sign in a user that already has a Spritz account, or if you have lost access to their API key. In this case, you can reauthorize the user by providing their email. The process is that we will send the user an OTP code to their email, and then the user must pass that code on to you to confirm that they are allowing you to interact with their account on their behalf.
141
+ If you need to recover a user's API key (e.g., the user already has a Spritz account, or you've lost access), use the OTP reauthorization flow:
203
142
 
204
143
  ```typescript
144
+ // Request an OTP code sent to the user's email
205
145
  const { success } = await client.user.requestApiKey('bilbo@shiremail.net')
206
146
 
147
+ // Confirm with the OTP code the user provides
207
148
  const { apiKey, userId, email } = await client.user.authorizeApiKeyWithOTP({
208
- email: 'bilbo@shiremail.net',
209
- otp: '123456',
149
+ email: 'bilbo@shiremail.net',
150
+ otp: '123456',
210
151
  })
211
152
  ```
212
153
 
213
- ### Basic User Data
214
-
215
- Use this to fetch the user's basic data
154
+ ### User Data
216
155
 
217
156
  ```typescript
218
157
  const userData = await client.user.getCurrentUser()
219
158
  ```
220
159
 
221
- ### User Verification
222
-
223
- **Purpose**: To ensure users are properly identified before interacting with the Spritz platform.
224
-
225
- ### Overview
226
-
227
- All users must undergo basic identity verification before they can engage with the Spritz platform's features.
228
-
229
- ### Process
160
+ ### Identity Verification
230
161
 
231
- 1. **User Creation**: Upon the creation of a new user, their default verification status will be set to `NotStarted`.
162
+ All users must complete identity verification before using the platform. New users start with a verification status of `NotStarted`.
232
163
 
233
- 2. **Checking Verification Status**: The user's verification data is included in the `getCurrentUser` response, including verification status, verification URL, verified country, and retry capability.
164
+ The user's verification data is included in the `getCurrentUser` response, including verification status, verification URL, verified country, and retry capability.
234
165
 
235
- 3. **Verification Transition**: Once a user completes the identity verification process, their status will change from `NotStarted` to `Verified`. Only then can the user fully interact with the platform.
236
-
237
- 4. **Getting Verification URL**: The verification URL is included in the user data response and is essential for the user to proceed with their identity verification.
238
-
239
- ### How to Present Verification Flow to the User
240
-
241
- Spritz offers two methods for integrating KYC verification, both using the `getVerificationParams()` method:
166
+ #### Getting Verification Parameters
242
167
 
243
168
  ```typescript
244
- // Get verification parameters from Spritz
245
169
  const verificationParams = await client.user.getVerificationParams()
246
170
 
247
- // The response includes:
171
+ // Returns:
248
172
  // - inquiryId: Unique identifier for this verification inquiry
249
173
  // - verificationUrl: URL for hosted verification
250
- // - sessionToken: Token for use with Plaid Link SDK
174
+ // - sessionToken: Token for use with Persona's Embedded Flow
251
175
  // - verificationUrlExpiresAt: Expiration timestamp for the verification URL
252
176
  ```
253
177
 
254
- #### Method 1: Verification URL (Simple Integration)
178
+ #### Option 1: Verification URL
255
179
 
256
- Use the `verificationUrl` from `getVerificationParams()` for a straightforward integration where Spritz handles the entire verification flow:
180
+ The simplest integration redirect the user to the hosted verification flow:
257
181
 
258
182
  ```typescript
259
- const verificationParams = await client.user.getVerificationParams()
260
- const verificationUrl = verificationParams.verificationUrl
261
- const expiresAt = verificationParams.verificationUrlExpiresAt
262
-
263
- // Important: The verification URL is short-lived and single-use
264
- // - Check the expiration with verificationUrlExpiresAt before using
265
- // - Once accessed, the URL becomes invalid
266
- // - If verification is not completed, call getVerificationParams() again for a new URL
267
-
268
- // Use the verification URL in your application:
269
- // - Browser: Open the URL in a new browser tab
270
- // - In-App: Embed the URL in an iframe within your application
271
- // - Mobile: Open the URL in a native mobile web view
272
- // - Email: Send users an email containing the link
273
- ```
274
-
275
- **Note**: The verification URL can only be used once. If the user doesn't complete verification after accessing the URL, you'll need to call `getVerificationParams()` again to generate a fresh URL and session.
276
-
277
- #### Method 2: Embedded Flow (Advanced Integration)
183
+ const { verificationUrl, verificationUrlExpiresAt } = await client.user.getVerificationParams()
278
184
 
279
- For more control over the verification experience, use the `inquiryId` and `sessionToken` (if present) from `getVerificationParams()` with the Persona Embedded Flow:
280
-
281
- ```typescript
282
- const verificationParams = await client.user.getVerificationParams()
283
- const inquiryId = verificationParams.inquiryId
284
- const sessionToken = verificationParams.sessionToken // May be null for some flows
285
-
286
- // Use the inquiryId (and sessionToken if present) with Persona's Embedded Flow
287
- // to create a custom verification experience
288
- // This allows you to:
289
- // - Customize the UI/UX of the verification process
290
- // - Handle callbacks and events directly
291
- // - Integrate verification seamlessly into your application flow
292
- // - Build a native mobile experience using Persona's mobile SDKs
185
+ // Open in a browser tab, iframe, or mobile web view.
186
+ // The URL is single-use and short-lived. If it expires or the user
187
+ // doesn't complete verification, call getVerificationParams() again.
293
188
  ```
294
189
 
295
- The embedded flow method is ideal when you want to:
296
-
297
- - Maintain full control over the user experience
298
- - Integrate verification directly into your app without redirects
299
- - Handle verification events and callbacks programmatically
300
- - Track and resume verification sessions with the inquiryId
301
-
302
- See the [Persona Embedded Flow documentation](https://docs.withpersona.com/quickstart-embedded-flow) for detailed integration instructions with the inquiryId and sessionToken.
303
-
304
- ### Verification Metadata (Failed Verifications)
190
+ #### Option 2: Embedded Flow
305
191
 
306
- When a user's verification fails, Spritz now provides additional metadata to help understand the failure reason and provide better user experience. This metadata is particularly useful for handling duplicate identity scenarios.
192
+ For full control over the UX, use the `inquiryId` and `sessionToken` with [Persona's Embedded Flow](https://docs.withpersona.com/quickstart-embedded-flow):
307
193
 
308
- #### Understanding Verification Metadata
309
-
310
- The verification metadata is available when a verification has failed and includes:
311
-
312
- - **`failureReason`**: The specific reason why the verification failed
313
- - **`details.matchedEmail`**: For duplicate identity failures, shows the email of the matched user (only if created through the same integration)
314
-
315
- #### Verification Failure Reasons
316
-
317
- The following verification failure reasons may be returned:
194
+ ```typescript
195
+ const { inquiryId, sessionToken } = await client.user.getVerificationParams()
318
196
 
319
- - **`verify_sms`**: SMS verification failed
320
- - **`documentary_verification`**: Document verification failed
321
- - **`risk_check`**: Risk assessment check failed
322
- - **`kyc_check`**: KYC (Know Your Customer) check failed
323
- - **`watchlist_screening`**: Watchlist screening check failed
324
- - **`selfie_check`**: Selfie verification check failed
325
- - **`address_invalid`**: Provided address is invalid
326
- - **`duplicate_identity`**: Identity already exists in the system
197
+ // Use inquiryId (and sessionToken if present) with Persona's SDK
198
+ // to embed the verification flow directly in your app.
199
+ ```
327
200
 
328
- #### Duplicate Identity Handling
201
+ #### Handling Verification Failures
329
202
 
330
- When a verification fails due to `duplicate_identity`, the system detects that the user has already been verified under a different account. The `matchedEmail` field helps determine:
203
+ When verification fails, the `verificationMetadata` field on the user object provides the failure reason:
331
204
 
332
- - **If `matchedEmail` is populated**: The duplicate user was created through your integration
333
- - **If `matchedEmail` is `null`**: The duplicate user was created through a different integration (e.g., the main Spritz app)
205
+ | Failure Reason | Description |
206
+ | -------------------------- | ---------------------------- |
207
+ | `verify_sms` | SMS verification failed |
208
+ | `documentary_verification` | Document verification failed |
209
+ | `risk_check` | Risk assessment failed |
210
+ | `kyc_check` | KYC check failed |
211
+ | `watchlist_screening` | Watchlist screening failed |
212
+ | `selfie_check` | Selfie verification failed |
213
+ | `address_invalid` | Invalid address |
214
+ | `duplicate_identity` | Identity already exists |
334
215
 
335
- This allows you to provide appropriate guidance to your users:
216
+ For `duplicate_identity` failures, `matchedEmail` indicates whether the duplicate was created through your integration:
336
217
 
337
218
  ```typescript
338
219
  const userData = await client.user.getCurrentUser()
339
220
 
340
221
  if (userData.verificationMetadata?.failureReason === 'duplicate_identity') {
341
- const matchedEmail = userData.verificationMetadata.details.matchedEmail
342
-
343
- if (matchedEmail) {
344
- // User exists within your integration
345
- console.log(`This identity is already verified with account: ${matchedEmail}`)
346
- // Guide user to use their existing account
347
- } else {
348
- // User exists in Spritz but not in your integration
349
- console.log('This identity is already verified with another Spritz account')
350
- // Inform user they need to use their original Spritz account
351
- }
222
+ const matchedEmail = userData.verificationMetadata.details.matchedEmail
223
+
224
+ if (matchedEmail) {
225
+ // Duplicate exists within your integration — guide user to their existing account
226
+ console.log(`Already verified as: ${matchedEmail}`)
227
+ } else {
228
+ // Duplicate exists in a different integration (e.g., the main Spritz app)
229
+ console.log('Identity already verified with another Spritz account')
230
+ }
352
231
  }
353
232
  ```
354
233
 
355
- ## Payment Flow
356
-
357
- ### Basic payment flow
358
-
359
- Execute a payment in a few simple steps:
360
-
361
- 1. **Select an Account**: Choose the account you wish to pay to.
362
- 2. **Initiate Payment Request**: Use the account's ID, your desired payment amount, and the chosen blockchain network to create a payment request.
363
- 3. **Retrieve Transaction Data**: Use the `getWeb3PaymentParams` method to obtain the necessary transaction data for fulfilling the payment request.
364
- 4. **Blockchain Transaction**: Issue the required blockchain transaction from the user's wallet.
365
- 5. **Payment Confirmation**: After blockchain transaction confirmation, check the status of the TradFi payment.
366
-
367
- ### Note on Issuing the Blockchain Transaction
368
-
369
- For Spritz to process a TradFi payment to an account, we need to receive a blockchain transaction on our smart contract, which provides us the crypto funds. As an integrator, it's essential to manage how the blockchain transaction is initiated from the user's wallet to Spritz.
370
-
371
- - **Wallet Apps**: If your application functions as a wallet, prompt the user to sign a transaction using data from `getWeb3PaymentParams`.
372
- - **Web-based Dapps**: Use your existing connection to the user's wallet to prompt a transaction.
373
-
374
- If your application doesn't have a connection to the user's wallet, consider implementing one. Some popular options include:
375
-
376
- - [Web3Modal (Web-based)](https://github.com/WalletConnect/web3modal)
377
- - [Web3Modal (React Native)](https://github.com/WalletConnect/modal-react-native)
378
- - [Web3-Onboard](https://onboard.blocknative.com/docs/overview/introduction#features)
379
-
380
- ### Example
381
-
382
- ```typescript
383
- // Fetch all bank accounts for the user
384
- const bankAccounts = await client.bankAccount.list()
385
-
386
- // Choose a bank account to use for the payment request
387
- const account = bankAccounts[0]
388
-
389
- // Create a payment request for the selected bank account
390
- const paymentRequest = await client.paymentRequest.create({
391
- amount: 100,
392
- accountId: account.id,
393
- network: PaymentNetwork.Ethereum,
394
- })
395
-
396
- // Retrieve the transaction data required to issue a blockchain transaction
397
- const transactionData = await client.paymentRequest.getWeb3PaymentParams({
398
- paymentRequest,
399
- paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC on mainnet
400
- })
401
-
402
- /**
403
- * Issue blockchain transaction with the transaction data
404
- * and wait for confirmation
405
- **/
406
-
407
- // Retrieve the payment issued for the payment request to check the payment status and confirmation
408
- const payment = await client.payment.getForPaymentRequest(paymentRequest.id)
409
- ```
410
-
411
234
  ## Accounts
412
235
 
413
- Spritz emphasizes its capabilities in account handling and payment processing.
414
-
415
- ### Account Types
416
-
417
- Spritz supports four distinct types of accounts:
418
-
419
- 1. **Bank Account**
420
- 2. **Debit Card**
421
- 3. **Bill**
422
- 4. **Virtual Card**
423
-
424
- Though each account type possesses its unique creation process and specific properties, it's important to understand that all of them are uniformly termed as an "account" within the Spritz platform.
425
-
426
- ### Commonalities & Differences
427
-
428
- - **Common Properties**: Every type of account shares certain properties consistent across the platform.
429
- - **Unique Properties**: Each account type also has attributes specific to its nature and functionality.
430
-
431
- Recognizing these nuances is crucial for optimal interaction with the Spritz platform's account-related features.
236
+ Spritz supports four account types: **Bank Account**, **Debit Card**, **Bill**, and **Virtual Card**. All are referred to as "accounts" within the platform and share common properties (`id`, `type`, `userId`, `country`, `currency`, `createdAt`), with additional fields specific to each type.
432
237
 
433
238
  ### Bank Accounts
434
239
 
435
- Spritz offers a dedicated interface to manage bank accounts, allowing seamless listing and addition of bank account details for users.
436
-
437
- #### List user bank accounts
438
-
439
- To retrieve all bank accounts linked to a user:
240
+ #### List
440
241
 
441
242
  ```typescript
442
243
  const bankAccounts = await client.bankAccount.list()
443
244
  ```
444
245
 
445
- The `bankAccount.list()` method returns an array of user-linked bank accounts, complete with essential details to display in a UI and facilitate payments:
446
-
447
246
  ```typescript
448
- const bankAccounts = [{
449
- id: "62d17d3b377dab6c1342136e",
450
- name: "Precious Savings",
451
- type: "BankAccount",
452
- bankAccountType: "USBankAccount",
453
- bankAccountSubType: "Checking",
454
- userId: "62d17d3b377dab6c1342136e",
455
- accountNumber: "1234567",
456
- bankAccountDetails: {
457
- routingNumber: "00000123",
458
- }
459
- country: "US",
460
- currency: "USD",
461
- email: "bilbo@shiremail.net",
462
- institution: {
463
- id: "62d27d4b277dab3c1342126e",
464
- name: "Shire Bank",
465
- logo: "https://tinyurl.com/shire-bank-logo",
466
- },
467
- ownedByUser: true,
468
- createdAt: "2023-05-03T11:25:02.401Z",
469
- deliveryMethods: ['STANDARD', 'INSTANT']
470
- }]
247
+ // Example response
248
+ ;[
249
+ {
250
+ id: '62d17d3b377dab6c1342136e',
251
+ name: 'Precious Savings',
252
+ type: 'BankAccount',
253
+ bankAccountType: 'USBankAccount',
254
+ bankAccountSubType: 'Checking',
255
+ userId: '62d17d3b377dab6c1342136e',
256
+ accountNumber: '1234567',
257
+ bankAccountDetails: {
258
+ routingNumber: '00000123',
259
+ },
260
+ country: 'US',
261
+ currency: 'USD',
262
+ email: 'bilbo@shiremail.net',
263
+ institution: {
264
+ id: '62d27d4b277dab3c1342126e',
265
+ name: 'Shire Bank',
266
+ logo: 'https://tinyurl.com/shire-bank-logo',
267
+ },
268
+ ownedByUser: true,
269
+ createdAt: '2023-05-03T11:25:02.401Z',
270
+ deliveryMethods: ['STANDARD', 'INSTANT'],
271
+ },
272
+ ]
471
273
  ```
472
274
 
473
- #### Add US bank account
474
-
475
- Currently, Spritz supports the addition of US bank accounts:
476
-
477
- The input structure for adding a US bank account is defined as:
478
-
479
- ```typescript
480
- // Input arguments for creating a US bank account
481
- export interface USBankAccountInput {
482
- accountNumber: string
483
- email?: string | null
484
- name?: string | null
485
- ownedByUser?: boolean | null
486
- routingNumber: string
487
- subType: BankAccountSubType
488
- }
489
- ```
275
+ #### Create US Bank Account
490
276
 
491
277
  ```typescript
492
278
  import { BankAccountType, BankAccountSubType } from '@spritz-finance/api-client'
493
279
 
494
- const bankAccounts = await client.bankAccount.create(BankAccountType.USBankAccount, {
495
- accountNumber: '123456789',
496
- routingNumber: '987654321',
497
- name: 'Precious Savings',
498
- ownedByUser: true,
499
- subType: BankAccountSubType.Savings,
280
+ const bankAccount = await client.bankAccount.create(BankAccountType.USBankAccount, {
281
+ accountNumber: '123456789',
282
+ routingNumber: '987654321',
283
+ name: 'Precious Savings',
284
+ ownedByUser: true,
285
+ subType: BankAccountSubType.Savings,
500
286
  })
501
287
  ```
502
288
 
503
- #### Add Canadian bank account
504
-
505
- Currently, Spritz supports the addition of Canadian bank accounts:
506
-
507
- The input structure for adding a Canadian bank account is defined as:
289
+ Input fields:
508
290
 
509
291
  ```typescript
510
- // Input arguments for creating a Canadian bank account
511
- export interface CABankAccountInput {
512
- accountNumber: string
513
- email?: string
514
- name: string
515
- ownedByUser?: boolean | null
516
- transitNumber: string
517
- institutionNumber: string
518
- subType: BankAccountSubType
292
+ interface USBankAccountInput {
293
+ accountNumber: string
294
+ routingNumber: string
295
+ subType: BankAccountSubType
296
+ name?: string | null
297
+ email?: string | null
298
+ ownedByUser?: boolean | null
519
299
  }
520
300
  ```
521
301
 
302
+ #### Create Canadian Bank Account
303
+
522
304
  ```typescript
523
305
  import { BankAccountType, BankAccountSubType } from '@spritz-finance/api-client'
524
306
 
525
- const bankAccounts = await client.bankAccount.create(BankAccountType.CABankAccount, {
526
- accountNumber: '123456789',
527
- transitNumber: '12345',
528
- institutionNumber: '123',
529
- name: 'Precious Savings',
530
- ownedByUser: true,
531
- subType: BankAccountSubType.Savings,
307
+ const bankAccount = await client.bankAccount.create(BankAccountType.CABankAccount, {
308
+ accountNumber: '123456789',
309
+ transitNumber: '12345',
310
+ institutionNumber: '123',
311
+ name: 'Precious Savings',
312
+ ownedByUser: true,
313
+ subType: BankAccountSubType.Savings,
532
314
  })
533
315
  ```
534
316
 
535
- ### Debit Cards
317
+ Input fields:
318
+
319
+ ```typescript
320
+ interface CABankAccountInput {
321
+ accountNumber: string
322
+ transitNumber: string
323
+ institutionNumber: string
324
+ name: string
325
+ subType: BankAccountSubType
326
+ email?: string
327
+ ownedByUser?: boolean | null
328
+ }
329
+ ```
536
330
 
537
- Spritz provides support for adding debit cards as payment accounts, allowing users to make payments directly to their debit cards.
331
+ ### Debit Cards
538
332
 
539
- #### List user debit cards
333
+ Supported networks: **Visa** and **Mastercard**.
540
334
 
541
- To retrieve all debit cards linked to a user:
335
+ #### List
542
336
 
543
337
  ```typescript
544
338
  const debitCards = await client.debitCard.list()
545
339
  ```
546
340
 
547
- The `debitCard.list()` method returns an array of user-linked debit cards:
548
-
549
341
  ```typescript
550
- const debitCards = [
551
- {
552
- id: '62d17d3b377dab6c1342136e',
553
- type: 'DebitCard',
554
- name: 'My Visa Debit',
555
- userId: '62d17d3b377dab6c1342136e',
556
- country: 'US',
557
- currency: 'USD',
558
- payable: true,
559
- debitCardNetwork: 'Visa',
560
- expirationDate: '12/25',
561
- cardNumber: '4111111111111111',
562
- mask: '1111',
563
- createdAt: '2023-01-01T00:00:00Z',
564
- paymentCount: 5,
565
- externalId: 'ext-123',
566
- },
342
+ // Example response
343
+ ;[
344
+ {
345
+ id: '62d17d3b377dab6c1342136e',
346
+ type: 'DebitCard',
347
+ name: 'My Visa Debit',
348
+ userId: '62d17d3b377dab6c1342136e',
349
+ country: 'US',
350
+ currency: 'USD',
351
+ payable: true,
352
+ debitCardNetwork: 'Visa',
353
+ expirationDate: '12/25',
354
+ cardNumber: '4111111111111111',
355
+ mask: '1111',
356
+ createdAt: '2023-01-01T00:00:00Z',
357
+ paymentCount: 5,
358
+ externalId: 'ext-123',
359
+ },
567
360
  ]
568
361
  ```
569
362
 
570
- #### Add a debit card
571
-
572
- To add a new debit card for a user:
363
+ #### Create
573
364
 
574
365
  ```typescript
575
- import { DebitCardNetwork } from '@spritz-finance/api-client'
576
-
577
366
  const debitCard = await client.debitCard.create({
578
- name: 'My Visa Debit',
579
- cardNumber: '4111111111111111',
580
- expirationDate: '12/25',
367
+ cardNumber: '4111111111111111', // 13-19 digits
368
+ expirationDate: '12/25', // MM/YY
369
+ name: 'My Visa Debit', // optional
581
370
  })
582
371
  ```
583
372
 
584
- The input structure for adding a debit card is:
585
-
586
- ```typescript
587
- export interface DebitCardInput {
588
- name?: string | null // Optional name for the card
589
- cardNumber: string // Full card number (13-19 digits)
590
- expirationDate: string // Expiration date in MM/YY format
591
- }
592
- ```
593
-
594
- Supported debit card networks:
595
-
596
- - `Visa`
597
- - `Mastercard`
598
-
599
373
  ### Bills
600
374
 
601
- Spritz provides robust support for bills, allowing seamless management and interaction with user billing accounts. Below is a guide to the methods and functionalities specifically designed for handling bills within Spritz.
602
-
603
- #### List user bills
604
-
605
- To retrieve all bill accounts associated with a user:
375
+ #### List
606
376
 
607
377
  ```typescript
608
378
  const bills = await client.bill.list()
609
379
  ```
610
380
 
611
- The `bill.list()` method returns an array of user-associated bills, complete with essential details for display in a UI and for processing payments:
612
-
613
381
  ```typescript
614
- const bills = [
615
- {
616
- id: '62d17d3b377dab6c1342136e',
617
- name: 'Precious Credit Card',
618
- type: 'Bill',
619
- billType: 'CreditCard',
620
- userId: '62d17d3b377dab6c1342136e',
621
- mask: '4567',
622
- originator: 'User',
623
- payable: true,
624
- verifying: false,
625
- billAccountDetails: {
626
- balance: 240.23,
627
- amountDue: 28.34,
628
- openedAt: '2023-05-03T11:25:02.401Z',
629
- lastPaymentAmount: null,
630
- lastPaymentDate: null,
631
- nextPaymentDueDate: '2023-06-03T11:25:02.401Z',
632
- nextPaymentMinimumAmount: 28.34,
633
- lastStatementBalance: 180.23,
634
- remainingStatementBalance: null,
635
- },
636
- country: 'US',
637
- currency: 'USD',
638
- dataSync: {
639
- lastSync: '2023-05-03T11:25:02.401Z',
640
- syncStatus: 'Active',
641
- },
642
- institution: {
643
- id: '62d27d4b277dab3c1342126e',
644
- name: 'Shire Bank Credit Card',
645
- logo: 'https://tinyurl.com/shire-bank-logo',
382
+ // Example response
383
+ ;[
384
+ {
385
+ id: '62d17d3b377dab6c1342136e',
386
+ name: 'Precious Credit Card',
387
+ type: 'Bill',
388
+ billType: 'CreditCard',
389
+ userId: '62d17d3b377dab6c1342136e',
390
+ mask: '4567',
391
+ originator: 'User',
392
+ payable: true,
393
+ verifying: false,
394
+ billAccountDetails: {
395
+ balance: 240.23,
396
+ amountDue: 28.34,
397
+ openedAt: '2023-05-03T11:25:02.401Z',
398
+ lastPaymentAmount: null,
399
+ lastPaymentDate: null,
400
+ nextPaymentDueDate: '2023-06-03T11:25:02.401Z',
401
+ nextPaymentMinimumAmount: 28.34,
402
+ lastStatementBalance: 180.23,
403
+ remainingStatementBalance: null,
404
+ },
405
+ country: 'US',
406
+ currency: 'USD',
407
+ dataSync: {
408
+ lastSync: '2023-05-03T11:25:02.401Z',
409
+ syncStatus: 'Active',
410
+ },
411
+ institution: {
412
+ id: '62d27d4b277dab3c1342126e',
413
+ name: 'Shire Bank Credit Card',
414
+ logo: 'https://tinyurl.com/shire-bank-logo',
415
+ },
416
+ createdAt: '2023-05-03T11:25:02.401Z',
417
+ deliveryMethods: ['STANDARD'],
646
418
  },
647
- createdAt: '2023-05-03T11:25:02.401Z',
648
- deliveryMethods: ['STANDARD'],
649
- },
650
419
  ]
651
420
  ```
652
421
 
653
- #### Add US bill account
422
+ #### Create
654
423
 
655
- Currently, Spritz allows the addition of US bill accounts only. The process involves identifying the institution managing the bill and inputting the bill's account number. Here's a guide on how to add a bill for a user:
424
+ Adding a bill requires the institution ID and the account number:
656
425
 
657
426
  ```typescript
658
427
  import { BillType } from '@spritz-finance/api-client'
659
428
 
660
429
  const institutions = await client.institution.popularUSBillInstitutions(BillType.CreditCard)
661
- const billInstitution = institutions[0]
662
- const accountNumber = '12345678913213'
430
+ const bill = await client.bill.create(institutions[0].id, '12345678913213', BillType.CreditCard)
431
+ ```
432
+
433
+ #### Finding Bill Institutions
663
434
 
664
- const bill = await client.bill.create(billInstitution.id, accountNumber, BillType.CreditCard)
435
+ ```typescript
436
+ // Popular institutions (optionally filtered by bill type)
437
+ const popular = await client.institution.popularUSBillInstitutions()
438
+ const mortgages = await client.institution.popularUSBillInstitutions(BillType.Mortgage)
439
+
440
+ // Search by name
441
+ const results = await client.institution.searchUSBillInstitutions('american express')
442
+ const filtered = await client.institution.searchUSBillInstitutions(
443
+ 'american express',
444
+ BillType.CreditCard
445
+ )
665
446
  ```
666
447
 
667
- ### Virtual Card
448
+ ### Virtual Cards
668
449
 
669
- Spritz offers the ability to create virtual cards that users can fund using cryptocurrency. These virtual cards represent an alternative payment account offered by Spritz. To effectively interact with the Virtual Card feature, use the API endpoints detailed below.
450
+ Virtual cards are crypto-funded payment cards.
670
451
 
671
- #### Fetch a users virtual card
452
+ #### Fetch
672
453
 
673
- The fetch endpoint returns an object containing details associated with the virtual card. Importantly, this object excludes sensitive card information such as the card number and the CVV.
454
+ Returns card details excluding sensitive fields (card number, CVV):
674
455
 
675
456
  ```typescript
676
457
  const virtualCard = await client.virtualCard.fetch()
677
458
  ```
678
459
 
679
460
  ```typescript
680
- const virtualCard = {
461
+ // Example response
462
+ {
681
463
  id: '62d17d3b377dab6c1342136e',
682
464
  type: 'VirtualCard',
683
465
  virtualCardType: 'USVirtualDebitCard',
@@ -703,7 +485,7 @@ const virtualCard = {
703
485
  }
704
486
  ```
705
487
 
706
- #### Create a US virtual debit card
488
+ #### Create
707
489
 
708
490
  ```typescript
709
491
  import { VirtualCardType } from '@spritz-finance/api-client'
@@ -711,189 +493,71 @@ import { VirtualCardType } from '@spritz-finance/api-client'
711
493
  const virtualCard = await client.virtualCard.create(VirtualCardType.USVirtualDebitCard)
712
494
  ```
713
495
 
714
- #### Displaying sensitive card details
715
-
716
- To show the sensitive card details that users require for payment transactions, you must integrate our dedicated drop-in widget. This widget securely renders card details. Use the renderSecret, obtained from the standard fetch card endpoint, in conjunction with the user's API key.
717
-
718
- We currently support and maintain the following packages for the card rendering process:
719
-
720
- - [React Library](https://www.npmjs.com/package/@spritz-finance/react-secure-elements)
721
- - [React Native Library](https://www.npmjs.com/package/@spritz-finance/react-native-secure-elements)
722
-
723
- ## Address Book
724
-
725
- Each account created in Spritz is allocated a unique on-chain payment address for each network. Tokens transferred to this address will be picked up and credited to the account. A list of the addresses, one per network, is available under the `paymentAddresses` property. Refer to the Spritz UI for which tokens are accepted for these addresses -- generally, we accept at least USDC and USDT on all networks which we integrate with.
726
-
727
- ```typescript
728
- [
729
- {
730
- id: '62d17d3b377dab6c1342136e',
731
- name: 'Precious Credit Card',
732
- type: 'Bill',
733
- billType: 'CreditCard',
734
- ...
735
- paymentAddresses: [
736
- {
737
- network: 'ethereum',
738
- address: '0xc0ffee254729296a45a3885639AC7E10F9d54979',
739
- },
740
- {
741
- network: 'polygon',
742
- address: '0xc0ffee254729296a45a3885639AC7E10F9d54979',
743
- },
744
- ],
745
- },
746
- ]
747
- ```
748
-
749
- ## Account Management
750
-
751
- ### Renaming accounts
752
-
753
- #### Rename a bank account
754
-
755
- You can conveniently change the display name of a bank account using the following endpoint. The first argument specifies the ID of the bank account, while the second argument represents the desired new name for the account.
756
-
757
- ```typescript
758
- const updateAccount = await client.bankAccount.rename('62d17d3b377dab6c1342136e', 'My new account')
759
- ```
760
-
761
- #### Rename a debit card
762
-
763
- You can change the display name of a debit card:
764
-
765
- ```typescript
766
- const updatedCard = await client.debitCard.rename(
767
- '62d17d3b377dab6c1342136e',
768
- 'My primary debit card'
769
- )
770
- ```
771
-
772
- #### Rename a bill
496
+ #### Displaying Sensitive Card Details
773
497
 
774
- You can conveniently change the display name of a bill using the following endpoint. The first argument specifies the ID of the bill, while the second argument represents the desired new name for the account.
498
+ To render the full card number and CVV, use the `renderSecret` from the fetch response with one of the Spritz secure element libraries:
775
499
 
776
- ```typescript
777
- const updateAccount = await client.bill.rename('62d17d3b377dab6c1342136e', 'My first credit card')
778
- ```
779
-
780
- ### Deleting accounts
500
+ - [React](https://www.npmjs.com/package/@spritz-finance/react-secure-elements)
501
+ - [React Native](https://www.npmjs.com/package/@spritz-finance/react-native-secure-elements)
781
502
 
782
- #### Delete a bank account
503
+ ### Address Book
783
504
 
784
- To remove a bank account from a user's account, you can use the following endpoint. You only need to specify the ID of the bank account that you want to delete as an argument.
505
+ Each account is allocated a unique on-chain payment address per network. Tokens sent to these addresses are automatically credited to the account. Accepted tokens vary by network generally USDC and USDT at minimum.
785
506
 
786
507
  ```typescript
787
- await client.bankAccount.delete('62d17d3b377dab6c1342136e')
508
+ // Included in account responses
509
+ {
510
+ paymentAddresses: [
511
+ { network: 'ethereum', address: '0xc0ffee254729296a45a3885639AC7E10F9d54979' },
512
+ { network: 'polygon', address: '0xc0ffee254729296a45a3885639AC7E10F9d54979' },
513
+ ],
514
+ }
788
515
  ```
789
516
 
790
- #### Delete a debit card
791
-
792
- To remove a debit card from a user's account:
517
+ ### Renaming Accounts
793
518
 
794
519
  ```typescript
795
- await client.debitCard.delete('62d17d3b377dab6c1342136e')
520
+ await client.bankAccount.rename('account-id', 'New Name')
521
+ await client.debitCard.rename('card-id', 'New Name')
522
+ await client.bill.rename('bill-id', 'New Name')
796
523
  ```
797
524
 
798
- #### Delete a bill
799
-
800
- To remove a bill from a user's account, you can use the following endpoint. You only need to specify the ID of the bill that you want to delete as an argument.
525
+ ### Deleting Accounts
801
526
 
802
527
  ```typescript
803
- await client.bill.delete('62d17d3b377dab6c1342136e')
528
+ await client.bankAccount.delete('account-id')
529
+ await client.debitCard.delete('card-id')
530
+ await client.bill.delete('bill-id')
804
531
  ```
805
532
 
806
- ## Bill Institutions
533
+ ## Payments (Off-ramp)
807
534
 
808
- When adding a new bill for a user, we need to provide a reference to the institution who holds the account for the user. As an example, if a user wanted to add their Chase Visa Credit Card to their Spritz account, the Institution of the account would be `Chase Credit Cards` and then the account number provided would be the 16-digit card number for their credit card.
535
+ ### Payment Flow
809
536
 
810
- Spritz exposes several endpoints to help users find the Institutions of their bill accounts.
811
-
812
- ### Fetching popular bill institutions
813
-
814
- ```typescript
815
- const popularInstitutions = await client.institution.popularUSBillInstitutions()
537
+ 1. **Select an account** choose the bank account, debit card, or bill to pay.
538
+ 2. **Create a payment request** — specify amount, account ID, and blockchain network.
539
+ 3. **Get transaction data** — call `getWeb3PaymentParams` (EVM) or `getSolanaPaymentParams` (Solana).
540
+ 4. **Execute the blockchain transaction** — sign and submit from the user's wallet.
541
+ 5. **Check payment status** — query the resulting fiat payment.
816
542
 
817
- // Optionally filter by a specific bill type
818
- const popularInstitutions = await client.institution.popularUSBillInstitutions(BillType.Mortgage)
819
- ```
543
+ > Your application needs a connection to the user's wallet to sign transactions. If you don't have one, consider [Web3Modal](https://github.com/WalletConnect/web3modal) or [Web3-Onboard](https://onboard.blocknative.com/docs/overview/introduction#features).
820
544
 
821
- ### Searching for bill institutions by name
545
+ ### Creating a Payment Request
822
546
 
823
547
  ```typescript
824
- const institutions = await client.institution.searchUSBillInstitutions('american express')
825
-
826
- // Optionally filter by a specific bill type
827
- const institutions = await client.institution.searchUSBillInstitutions(
828
- 'american express',
829
- BillType.CreditCard
830
- )
831
- ```
832
-
833
- ## Payment Requests
834
-
835
- A payment request refers to the intent to initiate a payment to a specific account. Once a payment request is created, a blockchain transaction is required to fulfill it. After the blockchain transaction settles, the payment request is completed, and a fiat payment is issued to the designated account.
836
-
837
- ### Create a payment request
838
-
839
- To initiate a payment request for a specific account, you can use the following functionality. The required inputs for creating a payment request include the ID of the account to be paid, the amount of the fiat payment in USD, and the network on which the blockchain transaction will settle.
840
-
841
- #### Amount Mode
842
-
843
- When creating a payment request, you can specify how the amount should be calculated using the `amountMode` parameter:
844
-
845
- - **`TOTAL_AMOUNT`**: The payer covers the entire amount including fees. The specified amount is the total that will be deducted from the payer's wallet.
846
- - **`AMOUNT_RECEIVED`** (default): The payment that arrives in the bank account excludes fees. The specified amount is what the recipient will receive, and fees are added on top.
847
-
848
- This allows you to control whether fees are included in or added to the specified amount.
548
+ import { PaymentNetwork, AmountMode } from '@spritz-finance/api-client'
849
549
 
850
- #### Fee Subsidies (Integrator Feature)
851
-
852
- Integrators can subsidize transaction fees on behalf of their users. When enabled, you can cover part or all of the transaction fees, which Spritz will invoice to you separately.
853
-
854
- > **Note**: Fee subsidies are a gated feature and must be enabled by the Spritz team before use. Contact Spritz to request access.
855
-
856
- **Parameters:**
857
-
858
- - **`feeSubsidyPercentage`** (string): The percentage of the transaction fee you want to subsidize for the user. For example, `"100"` covers the entire fee, `"50"` covers half.
859
- - **`maxFeeSubsidyAmount`** (string, optional): The maximum dollar amount you're willing to subsidize per transaction. If the fee exceeds this cap, the user pays the difference.
860
-
861
- **How it works:**
862
-
863
- 1. Set `feeSubsidyPercentage` to define what portion of fees you'll cover
864
- 2. Optionally set `maxFeeSubsidyAmount` to cap your exposure
865
- 3. Spritz invoices you separately for the subsidized amounts
866
- 4. Users see reduced or zero fees on their transactions
867
-
868
- **Example:**
869
-
870
- ```typescript
871
- // Cover 100% of fees up to $5 per transaction
872
550
  const paymentRequest = await client.paymentRequest.create({
873
- amount: 100,
874
- accountId: account.id,
875
- network: PaymentNetwork.Ethereum,
876
- feeSubsidyPercentage: '100',
877
- maxFeeSubsidyAmount: '5',
551
+ amount: 100,
552
+ accountId: account.id,
553
+ network: PaymentNetwork.Ethereum,
554
+ deliveryMethod: 'INSTANT', // optional
555
+ amountMode: AmountMode.TOTAL_AMOUNT, // optional, defaults to AMOUNT_RECEIVED
878
556
  })
879
-
880
- // If transaction fee is $3: integrator pays $3, user pays $0
881
- // If transaction fee is $8: integrator pays $5, user pays $3
882
557
  ```
883
558
 
884
559
  ```typescript
885
- import {PaymentNetwork, AmountMode} from '@spritz-finance/api-client';
886
-
887
- const paymentRequest = await client.paymentRequest.create({
888
- amount: 100,
889
- accountId: account.id,
890
- network: PaymentNetwork.Ethereum,
891
- deliveryMethod: 'INSTANT',
892
- amountMode: AmountMode.TOTAL_AMOUNT // Optional, defaults to AMOUNT_RECEIVED
893
- });
894
-
895
560
  // Example response
896
-
897
561
  {
898
562
  id: '645399c8c1ac408007b12273',
899
563
  userId: '63d12d3B577fab6c6382136e',
@@ -903,108 +567,98 @@ const paymentRequest = await client.paymentRequest.create({
903
567
  feeAmount: 0,
904
568
  amountDue: 100,
905
569
  network: 'ethereum',
906
- createdAt: '2023-05-04T11:40:56.488Z'
570
+ createdAt: '2023-05-04T11:40:56.488Z',
907
571
  }
908
572
  ```
909
573
 
910
- ### Fulfil a payment request (EVM transactions)
574
+ #### Amount Mode
911
575
 
912
- After creating a payment request, you must issue a blockchain transaction to settle the payment request. For EVM compatible networks, this involves interacting with the SpritzPay smart contract (see: [SpritzPay deployments](https://docs.spritz.finance/docs/deployment-addresses)).
576
+ - **`AMOUNT_RECEIVED`** (default) the recipient receives the specified amount; fees are added on top.
577
+ - **`TOTAL_AMOUNT`** — the specified amount includes fees; the recipient receives less.
913
578
 
914
- To obtain the data needed for the transaction, you can use the following endpoint.
579
+ #### Fee Subsidies
915
580
 
916
- ```typescript
917
- import {PaymentNetwork} from '@spritz-finance/api-client';
581
+ Integrators can subsidize transaction fees on behalf of users. This is a gated feature — contact Spritz to enable it.
918
582
 
583
+ ```typescript
919
584
  const paymentRequest = await client.paymentRequest.create({
920
- amount: 100,
921
- accountId: account.id,
922
- network: PaymentNetwork.Ethereum,
923
- });
585
+ amount: 100,
586
+ accountId: account.id,
587
+ network: PaymentNetwork.Ethereum,
588
+ feeSubsidyPercentage: '100', // percentage of fee to cover
589
+ maxFeeSubsidyAmount: '5', // cap per transaction in USD
590
+ })
591
+
592
+ // Fee = $3 → integrator pays $3, user pays $0
593
+ // Fee = $8 → integrator pays $5, user pays $3
594
+ ```
595
+
596
+ Subsidized amounts are invoiced to the integrator separately.
924
597
 
598
+ ### Fulfilling a Payment — EVM
599
+
600
+ For EVM networks, you interact with the SpritzPay smart contract ([deployment addresses](https://docs.spritz.finance/docs/deployment-addresses)):
601
+
602
+ ```typescript
925
603
  const transactionData = await client.paymentRequest.getWeb3PaymentParams({
926
- paymentRequest,
927
- paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC on mainnet
604
+ paymentRequest,
605
+ paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
928
606
  })
929
607
 
930
608
  // Example response
931
-
932
609
  {
933
610
  contractAddress: '0xbF7Abc15f00a8C2d6b13A952c58d12b7c194A8D0',
934
611
  method: 'payWithToken',
935
- calldata: '0xd71d9632000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000064539a31c1ac408007b12277',
612
+ calldata: '0xd71d9632...',
936
613
  value: null,
937
614
  requiredTokenInput: '100000000',
938
615
  }
939
616
  ```
940
617
 
941
- The contract address (to), calldata (data), and value are the primary components used to execute the blockchain transaction. You can use the `requiredTokenInput` to verify that the user's wallet has sufficient funds to complete the payment before initiating the transaction.
618
+ Use `contractAddress` as `to`, `calldata` as `data`, and `value` to build the transaction. Check `requiredTokenInput` against the user's balance before submitting.
942
619
 
943
- ### Fulfil a payment request (Solana transactions)
944
-
945
- For Solana payments, you need to obtain a versioned transaction that can be signed and submitted to the Solana network.
620
+ ### Fulfilling a Payment Solana
946
621
 
947
622
  ```typescript
948
- import {PaymentNetwork} from '@spritz-finance/api-client';
949
-
950
- const paymentRequest = await client.paymentRequest.create({
951
- amount: 100,
952
- accountId: account.id,
953
- network: PaymentNetwork.Solana,
954
- });
955
-
956
623
  const transactionData = await client.paymentRequest.getSolanaPaymentParams({
957
- paymentRequest,
958
- paymentTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC on Solana
959
- signer: 'YourSolanaWalletAddress...',
624
+ paymentRequest,
625
+ paymentTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
626
+ signer: 'YourSolanaWalletAddress',
960
627
  })
961
628
 
962
629
  // Example response
963
-
964
630
  {
965
- versionedTransaction: VersionedTransaction, // Deserialized transaction ready to sign
966
- transactionSerialized: 'base64EncodedTransaction...' // Base64 encoded transaction
631
+ versionedTransaction: VersionedTransaction, // ready to sign
632
+ transactionSerialized: 'base64...', // base64-encoded alternative
967
633
  }
968
634
  ```
969
635
 
970
- The `versionedTransaction` is a deserialized Solana transaction that can be signed with your wallet and submitted to the network. The `transactionSerialized` contains the same transaction in base64 encoded format if needed for your implementation.
971
-
972
- ### Transaction fees
636
+ ### Transaction Fees
973
637
 
974
- Transaction fees are applied once the monthly transaction volume exceeds $100. To determine the fee amount for a specific payment value, you can use the following endpoint.
638
+ Fees apply once monthly volume exceeds $100. To check the fee for a given amount:
975
639
 
976
640
  ```typescript
977
- const fees = await client.paymentRequest.transactionPrice(101)
978
-
979
- // Example response
980
- 0.01
641
+ const fee = await client.paymentRequest.transactionPrice(101)
642
+ // Returns: 0.01
981
643
  ```
982
644
 
983
- ## Payments
984
-
985
- Payments represent a fiat payment that has been issued to the account. Once the status of the Payment Request has moved to `Confirmed` then the Payment will be created.
986
-
987
- ### Transaction Details
645
+ ### Retrieving Payments
988
646
 
989
- Payments now include transaction details about the blockchain transaction that fulfilled the payment. When a payment is completed, the `transaction` field contains:
647
+ Payments are created once a payment request reaches `Confirmed` status.
990
648
 
991
- - **hash**: The blockchain transaction hash
992
- - **from**: The wallet address that sent the payment
993
- - **asset**: The token contract address used for payment
994
- - **value**: The amount transferred (in the token's smallest unit)
995
- - **network**: The blockchain network used (e.g., 'ethereum', 'polygon', etc.)
996
-
997
- This allows you to track the on-chain transaction that corresponds to each fiat payment.
649
+ ```typescript
650
+ // By payment ID
651
+ const payment = await client.payment.fetchById('6368e3a3ec516e9572bbd23b')
998
652
 
999
- ### Retrieve a payment by ID
653
+ // By payment request ID
654
+ const payment = await client.payment.getForPaymentRequest(paymentRequest.id)
1000
655
 
1001
- You can fetch a payment directly by its ID:
656
+ // All payments for an account
657
+ const payments = await client.payment.listForAccount(account.id)
658
+ ```
1002
659
 
1003
660
  ```typescript
1004
- const payment = await client.payment.fetchById('6368e3a3ec516e9572bbd23b');
1005
-
1006
661
  // Example response
1007
-
1008
662
  {
1009
663
  id: '6368e3a3ec516e9572bbd23b',
1010
664
  userId: '63d12d3B577fab6c6382136e',
@@ -1014,505 +668,222 @@ const payment = await client.payment.fetchById('6368e3a3ec516e9572bbd23b');
1014
668
  feeAmount: null,
1015
669
  createdAt: '2022-11-07T10:53:23.998Z',
1016
670
  transaction: {
1017
- hash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
671
+ hash: '0x1234...abcdef',
1018
672
  from: '0xYourWalletAddress',
1019
673
  asset: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1020
674
  value: 100000000,
1021
- network: 'ethereum'
1022
- }
675
+ network: 'ethereum',
676
+ },
1023
677
  }
1024
678
  ```
1025
679
 
1026
- ### Retrieve the payment for a payment request
1027
-
1028
- ```typescript
1029
- import {PaymentNetwork} from '@spritz-finance/api-client';
1030
-
1031
- const paymentRequest = await client.paymentRequest.create({
1032
- amount: 100,
1033
- accountId: account.id,
1034
- network: PaymentNetwork.Ethereum,
1035
- });
1036
-
1037
- const payment = await client.payment.getForPaymentRequest(paymentRequest.id);
1038
-
1039
- // Example response
1040
-
1041
- {
1042
- id: '6368e3a3ec516e9572bbd23b',
1043
- userId: '63d12d3B577fab6c6382136e',
1044
- status: 'PENDING',
1045
- accountId: '6322445f10d3f4d19c4d72fe',
1046
- amount: 100,
1047
- feeAmount: null,
1048
- createdAt: '2022-11-07T10:53:23.998Z',
1049
- transaction: null // Will be populated once the payment is fulfilled
1050
- }
1051
-
1052
- ```
1053
-
1054
- ### Retrieve all payments for an account
1055
-
1056
- ```typescript
1057
- const payments = await client.payment.listForAccount(account.id)
1058
-
1059
- // Example response
1060
-
1061
- [
1062
- {
1063
- id: '6368e3a3ec516e9572bbd23b',
1064
- userId: '63d12d3B577fab6c6382136e',
1065
- status: 'COMPLETED',
1066
- accountId: '6322445f10d3f4d19c4d72fe',
1067
- amount: 100,
1068
- feeAmount: null,
1069
- createdAt: '2022-11-07T10:53:23.998Z',
1070
- transaction: {
1071
- __typename: 'BlockchainTransaction',
1072
- hash: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
1073
- from: '0xYourWalletAddress',
1074
- asset: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1075
- value: 100000000,
1076
- network: 'ethereum'
1077
- }
1078
- },
1079
- ]
1080
- ```
1081
-
1082
- ### Get payment limits for an account
1083
-
1084
- Retrieve the payment limits for a specific account, including the per-transaction limit and the remaining daily volume.
680
+ ### Payment Limits
1085
681
 
1086
682
  ```typescript
1087
683
  const limits = await client.payment.getPaymentLimits(account.id)
1088
684
 
1089
685
  // Example response
1090
686
  {
1091
- perTransaction: 20000,
1092
- dailyRemainingVolume: 150000,
1093
- }
1094
- ```
1095
-
1096
- ## Onramp Payments
1097
-
1098
- Onramp Payments are orders to buy crypto stablecoins with a bank transfer. Upon creating an onramp payment, you will receive deposit instructions to fulfill that order. When the bank transfer has been received and disbursed, the status of that onramp payment will change.
1099
-
1100
- ### Create onramp payment
1101
-
1102
- ```typescript
1103
- const onrampPayment = await client.onrampPayment.create({
1104
- token: 'USDC' // Supported: currently only 'USDC'
1105
- network: 'ethereum' // supported: 'ethereum', 'polygon', 'avalanche'
1106
- amount: 100, // How much token to purchase (100 USDC)
1107
- address: '0xbB76483e33e01315438D8F6CF1Aee9C9b85f433b', // Wallet address to disburse tokens to
1108
- paymentMethod: 'ACH' // 'WIRE' or 'ACH'
1109
- });
1110
-
1111
- // Example response
1112
-
1113
- {
1114
- "id": "653fab35ad263e5ae8b0e605",
1115
- "amount": 100,
1116
- "feeAmount": 1.5,
1117
- "depositInstructions": {
1118
- "amount": 101.5,
1119
- "currency": "USD",
1120
- "bankName": "Bank of Nowhere",
1121
- "bankAddress": "1800 North Pole St., Orlando, FL 32801",
1122
- "bankBeneficiaryName": "Bridge Ventures Inc",
1123
- "bankRoutingNumber": "123456789",
1124
- "bankAccountNumber": "11223344556677",
1125
- "paymentMethod": "WIRE",
1126
- "depositMessage": "BVI72D90851F051F4189",
1127
- },
1128
- "network": "ethereum",
1129
- "token": "USDC",
1130
- "address": "0xbb76483e33e01315438d8f6cf1aee9c9b85f433b",
1131
- "status": "AWAITING_FUNDS",
1132
- "createdAt": "2023-10-30T13:10:13.521Z",
687
+ perTransaction: 20000,
688
+ dailyRemainingVolume: 150000,
1133
689
  }
1134
-
1135
-
1136
690
  ```
1137
691
 
1138
- ### Retrieve all onramp payments for an account
1139
-
1140
- ```typescript
1141
- const payments =
1142
- await client.onrampPayment.list()[
1143
- // Example response
1144
-
1145
- {
1146
- id: '653fab35ad263e5ae8b0e605',
1147
- amount: 100,
1148
- feeAmount: 1.5,
1149
- depositInstructions: {
1150
- amount: 101.5,
1151
- currency: 'USD',
1152
- bankName: 'Bank of Nowhere',
1153
- bankAddress: '1800 North Pole St., Orlando, FL 32801',
1154
- bankBeneficiaryName: 'Bridge Ventures Inc',
1155
- bankRoutingNumber: '123456789',
1156
- bankAccountNumber: '11223344556677',
1157
- paymentMethod: 'WIRE',
1158
- depositMessage: 'BVI72D90851F051F4189',
1159
- },
1160
- network: 'ethereum',
1161
- token: 'USDC',
1162
- address: '0xbb76483e33e01315438d8f6cf1aee9c9b85f433b',
1163
- status: 'AWAITING_FUNDS',
1164
- createdAt: '2023-10-30T13:10:13.521Z',
1165
- }
1166
- ]
1167
- ```
1168
-
1169
- ## Webhooks
1170
-
1171
- Instead of making a request to get information, webhooks send information to your specified endpoint as soon as an event occurs. Spritz's integration offers a variety of webhook events that can be crucial for maintaining data integrity and responsiveness in applications. Let's dive into how you can best utilize these.
1172
-
1173
- ### Supported webhook events
1174
-
1175
- Spritz currently supports the following webhook events:
1176
-
1177
- #### Account Events
1178
-
1179
- - `account.created`: Triggered when a new account is created.
1180
- - `account.updated`: Triggered when details of an account are updated.
1181
- - `account.deleted`: Triggered when an account is deleted.
1182
-
1183
- #### Payment Events
1184
-
1185
- - `payment.created`: Triggered when a new payment is initiated.
1186
- - `payment.updated`: Triggered when details of a payment are updated.
1187
- - `payment.completed`: Triggered when a payment is successfully completed.
1188
- - `payment.refunded`: Triggered when a payment is refunded.
1189
-
1190
- #### Verification Events
1191
-
1192
- - `verification.status.updated`: Triggered when a user's verification status changes.
1193
-
1194
- These events allow you to respond to changes in the account and payments for a user.
1195
-
1196
- ### Setting up webhooks
1197
-
1198
- To set up a webhook with Spritz, you'll need to provide:
692
+ ## On-ramp
1199
693
 
1200
- 1. **URL**: The endpoint URL where Spritz will send the webhook data.
1201
- 2. **Events**: The specific events you want to listen for.
1202
-
1203
- ```typescript
1204
- const webhook = await client.webhook.create({
1205
- url: 'https://my.webhook.url/spritz',
1206
- events: ['account.created', 'account.updated', 'account.deleted'],
1207
- })
1208
- ```
1209
-
1210
- Upon receiving a webhook, your server will get a payload with the following structure:
1211
-
1212
- ```json
1213
- {
1214
- "userId": "user-id-here",
1215
- "id": "resource-id-here",
1216
- "eventName": "name-of-the-event-here"
1217
- }
1218
- ```
1219
-
1220
- ### Managing webhooks
1221
-
1222
- #### List all webhooks
1223
-
1224
- To retrieve all webhooks configured for your integration:
1225
-
1226
- ```typescript
1227
- const webhooks = await client.webhook.list()
1228
- // Returns an array of webhook configurations
1229
- ```
1230
-
1231
- #### Delete a webhook
1232
-
1233
- To delete a specific webhook by its ID:
1234
-
1235
- ```typescript
1236
- const deletedWebhook = await client.webhook.delete('webhook-id-here')
1237
- // Returns the deleted webhook object
1238
- ```
1239
-
1240
- ### Webhook security and signing
1241
-
1242
- Each webhook request is signed using an HMAC SHA256 signature, based on the exact JSON payload sent in the body. This signature is included in the Signature HTTP header of the request.
1243
-
1244
- The secret key used to compute the signature is the webhook secret you set when configuring your webhook integration. If you have not set a webhook secret, there will be no Signature header in the webhook request.
1245
-
1246
- You can verify webhook authenticity by computing the HMAC signature and comparing it to the Signature header included in the webhook request.
1247
-
1248
- #### Example: Verifying a webhook signature (Node.js)
1249
-
1250
- ```typescript
1251
- import { createHmac } from "crypto";
1252
-
1253
- const signature = createHmac("sha256", <YOUR_WEBHOOK_SECRET>)
1254
- .update(<REQUEST_BODY_AS_JSON_STRING>) // JSON.stringify(payload)
1255
- .digest("hex");
1256
- ```
1257
-
1258
- Ensure that the computed signature matches the Signature header received in the webhook request before processing the payload.
1259
-
1260
- ### Setting webhook secret
1261
-
1262
- To add or update a webhook secret for signing webhook requests:
1263
-
1264
- ```typescript
1265
- const result = await client.webhook.updateWebhookSecret('your-webhook-secret-here')
1266
- // Returns: { success: true }
1267
- ```
1268
-
1269
- This secret will be used to sign all subsequent webhook requests sent to your endpoint. Always store your webhook secret securely and never expose it in client-side code.
1270
-
1271
- ## On-ramp Setup Guide
1272
-
1273
- The on-ramp feature allows users to purchase cryptocurrency using traditional payment methods (ACH, Wire transfers). Before users can on-ramp, they must complete identity verification and accept terms of service.
694
+ The on-ramp feature allows users to purchase crypto stablecoins via ACH or wire transfer.
1274
695
 
1275
696
  ### Prerequisites
1276
697
 
1277
- Before a user can on-ramp, they must:
1278
-
1279
698
  1. Complete platform-level KYC (identity verification)
1280
699
  2. Accept the third-party on-ramp provider's Terms of Service
1281
- 3. Wait for the provider's KYC to process (happens automatically after accepting ToS)
1282
-
1283
- ### Checking User Access Capabilities
700
+ 3. Provider KYC processes automatically after ToS acceptance
1284
701
 
1285
- Use the `getUserAccess()` method to check what features are available to a user and what requirements they need to complete:
702
+ ### Checking User Access
1286
703
 
1287
704
  ```typescript
1288
- const accessCapabilities = await client.user.getUserAccess()
705
+ const access = await client.user.getUserAccess()
706
+
707
+ // Off-ramp capabilities
708
+ if (access.capabilities.offramp.active) {
709
+ console.log('Off-ramp features:', access.capabilities.offramp.features)
710
+ // US: 'us_bank_account', 'us_debit_card'
711
+ // CA: 'ca_bank_account'
712
+ }
1289
713
 
1290
- // Check if on-ramp is active
1291
- if (accessCapabilities.capabilities.onramp.active) {
1292
- console.log('User can on-ramp!')
1293
- console.log('Available features:', accessCapabilities.capabilities.onramp.features)
1294
- // Features may include: 'ach_purchase', 'wire_purchase'
714
+ // On-ramp capabilities
715
+ if (access.capabilities.onramp.active) {
716
+ console.log('On-ramp features:', access.capabilities.onramp.features)
717
+ // May include: 'ach_purchase', 'wire_purchase'
1295
718
  } else {
1296
- console.log('User needs to complete requirements:')
1297
- accessCapabilities.capabilities.onramp.requirements.forEach((req) => {
1298
- console.log(`- ${req.type}: ${req.description}`)
1299
- if (req.actionUrl) {
1300
- console.log(` Action URL: ${req.actionUrl}`)
719
+ for (const req of access.capabilities.onramp.requirements) {
720
+ console.log(`${req.type}: ${req.description}`)
1301
721
  }
1302
- })
1303
722
  }
1304
723
  ```
1305
724
 
1306
- ### Step-by-Step On-ramp Activation
725
+ ### Activation Steps
1307
726
 
1308
- #### 1. Check Initial Requirements
727
+ #### 1. Complete Platform KYC
1309
728
 
1310
729
  ```typescript
1311
730
  const access = await client.user.getUserAccess()
1312
731
 
1313
- // Check platform-level KYC first
1314
732
  if (!access.kycStatus.verified) {
1315
- // User needs to complete platform KYC
1316
- if (access.kycRequirement) {
1317
- if (access.kycRequirement.actionUrl) {
1318
- // Direct user to complete KYC
1319
- console.log('Complete KYC at:', access.kycRequirement.actionUrl)
733
+ if (access.kycRequirement?.actionUrl) {
734
+ console.log('Complete KYC at:', access.kycRequirement.actionUrl)
1320
735
  }
1321
- if (access.kycRequirement.status === 'failed' && access.kycRequirement.retryable) {
1322
- // User can retry failed verification
1323
- await client.user.retryFailedVerification()
736
+ if (access.kycRequirement?.status === 'failed' && access.kycRequirement.retryable) {
737
+ await client.user.retryFailedVerification()
1324
738
  }
1325
- }
1326
739
  }
1327
740
  ```
1328
741
 
1329
742
  #### 2. Accept Terms of Service
1330
743
 
1331
- Once platform KYC is complete, the user needs to accept the third-party on-ramp provider's Terms of Service:
1332
-
1333
744
  ```typescript
1334
745
  const access = await client.user.getUserAccess()
1335
-
1336
- // Find the Terms of Service requirement
1337
746
  const tosRequirement = access.capabilities.onramp.requirements.find(
1338
- (req) => req.type === 'terms_acceptance'
747
+ (req) => req.type === 'terms_acceptance'
1339
748
  )
1340
749
 
1341
- if (tosRequirement && tosRequirement.actionUrl) {
1342
- // Use this URL to guide the customer towards Terms of Service acceptance
1343
- // You can embed this URL in an iFrame or display in a new browser window
1344
-
1345
- // For iFrame and WebView implementations:
1346
- // Listen to the postMessage event for the signedAgreementId
1347
- window.addEventListener('message', (event) => {
1348
- if (event.data.signedAgreementId) {
1349
- // Use the agreement ID to complete acceptance
1350
- await client.onramp.acceptTermsOfService(event.data.signedAgreementId)
1351
- }
1352
- })
1353
-
1354
- // Direct user to review the terms at tosRequirement.actionUrl
1355
- console.log('Terms of Service URL:', tosRequirement.actionUrl)
750
+ if (tosRequirement?.actionUrl) {
751
+ // Display tosRequirement.actionUrl in a browser tab, iframe, or webview.
752
+ // Listen for the signedAgreementId via postMessage:
753
+ window.addEventListener('message', (event) => {
754
+ if (event.data.signedAgreementId) {
755
+ await client.onramp.acceptTermsOfService(event.data.signedAgreementId)
756
+ }
757
+ })
1356
758
  }
1357
759
  ```
1358
760
 
1359
- #### 3. Provider KYC Processing (Automatic)
761
+ #### 3. Wait for Provider KYC
1360
762
 
1361
- After accepting the Terms of Service, the third-party provider's KYC process happens automatically in the background. When you accept the ToS, the platform automatically submits the user's existing KYC data to the provider. The integrator doesn't need to take any action - just monitor the status:
763
+ Provider KYC runs automatically after ToS acceptance. No action required monitor the status:
1362
764
 
1363
765
  ```typescript
1364
- // After accepting ToS, provider KYC is processed automatically
1365
- // You can monitor the status but no action is required
1366
766
  const access = await client.user.getUserAccess()
1367
-
1368
- // Check provider KYC status (for monitoring only)
1369
- const kycRequirement = access.capabilities.onramp.requirements.find(
1370
- (req) => req.type === 'identity_verification'
767
+ const kycReq = access.capabilities.onramp.requirements.find(
768
+ (req) => req.type === 'identity_verification'
1371
769
  )
1372
770
 
1373
- if (kycRequirement) {
1374
- switch (kycRequirement.status) {
1375
- case 'pending':
1376
- console.log('Provider KYC is being processed automatically')
1377
- break
1378
- case 'failed':
1379
- console.log('Provider KYC failed - user may need to retry')
1380
- break
1381
- default:
1382
- // KYC completed successfully if no requirement exists
1383
- console.log('Provider KYC complete!')
1384
- }
1385
- }
771
+ // kycReq is undefined when complete, otherwise check kycReq.status ('pending' | 'failed')
1386
772
  ```
1387
773
 
1388
- #### 4. Monitor Capability Updates
774
+ Use the `capabilities.updated` webhook event to be notified when the user's capabilities change.
1389
775
 
1390
- Use webhooks to be notified when user capabilities change:
776
+ ### Virtual Accounts
1391
777
 
1392
- ```typescript
1393
- // Set up a webhook to monitor capability updates
1394
- const webhook = await client.webhook.create({
1395
- url: 'https://your-server.com/webhook',
1396
- events: ['capabilities.updated'],
1397
- })
1398
-
1399
- // In your webhook handler:
1400
- // When you receive a 'capabilities.updated' event, check the user's access again
1401
- const updatedAccess = await client.user.getUserAccess()
1402
- if (updatedAccess.capabilities.onramp.active) {
1403
- console.log('User can now on-ramp!')
1404
- }
1405
- ```
1406
-
1407
- ### Creating Virtual Accounts
1408
-
1409
- Once on-ramp is active, users can create virtual accounts to receive funds:
778
+ Once on-ramp is active, users can create virtual accounts to receive fiat deposits:
1410
779
 
1411
780
  ```typescript
1412
781
  import { PaymentNetwork, onrampSupportedTokens } from '@spritz-finance/api-client'
1413
782
 
1414
783
  // Check supported tokens for a network
1415
- const supportedTokens = onrampSupportedTokens[PaymentNetwork.Ethereum]
1416
- console.log('Supported tokens on Ethereum:', supportedTokens)
1417
- // Output: ['USDC', 'USDT', 'DAI', 'USDP', 'PYUSD']
784
+ const tokens = onrampSupportedTokens[PaymentNetwork.Ethereum]
785
+ // ['USDC', 'USDT', 'DAI', 'USDP', 'PYUSD']
1418
786
 
1419
787
  // Create a virtual account
1420
788
  const virtualAccount = await client.virtualAccounts.create({
1421
- network: PaymentNetwork.Ethereum,
1422
- address: '0xYourEthereumAddress',
1423
- token: 'USDC',
789
+ network: PaymentNetwork.Ethereum,
790
+ address: '0xYourEthereumAddress',
791
+ token: 'USDC',
1424
792
  })
1425
793
 
1426
- // The virtual account includes deposit instructions
1427
- if (virtualAccount.depositInstructions) {
1428
- const instructions = virtualAccount.depositInstructions
1429
- console.log('Bank Name:', instructions.bankName)
1430
- console.log('Account Number:', instructions.bankAccountNumber)
1431
- console.log('Routing Number:', instructions.bankRoutingNumber)
1432
- console.log('Bank Address:', instructions.bankAddress)
1433
- // User sends wire/ACH to these details to fund their account
1434
- }
794
+ // Deposit instructions for funding via ACH/wire
795
+ const { bankName, bankAccountNumber, bankRoutingNumber, bankAddress } =
796
+ virtualAccount.depositInstructions
797
+
798
+ // List all virtual accounts
799
+ const accounts = await client.virtualAccounts.list()
1435
800
  ```
1436
801
 
1437
- ### Listing Virtual Accounts
802
+ ### Supported Tokens
1438
803
 
1439
- ```typescript
1440
- // Get all virtual accounts for the user
1441
- const accounts = await client.virtualAccounts.list()
804
+ | Network | Tokens |
805
+ | --------- | ---------------------------- |
806
+ | Ethereum | USDC, USDT, DAI, USDP, PYUSD |
807
+ | Polygon | USDC |
808
+ | Base | USDC |
809
+ | Arbitrum | USDC |
810
+ | Avalanche | USDC |
811
+ | Optimism | USDC |
812
+ | Solana | USDC, PYUSD |
813
+ | Tron | USDT |
814
+
815
+ ## Webhooks
816
+
817
+ ### Events
818
+
819
+ #### Account Events
820
+
821
+ - `account.created` — new account created
822
+ - `account.updated` — account details updated
823
+ - `account.deleted` — account deleted
824
+
825
+ #### Payment Events
1442
826
 
1443
- accounts.forEach((account) => {
1444
- console.log(`Network: ${account.network}`)
1445
- console.log(`Address: ${account.address}`)
1446
- console.log(`Token: ${account.token}`)
1447
- console.log(`Deposited: ${account.deposited}`)
827
+ - `payment.created` payment initiated
828
+ - `payment.updated` — payment details updated
829
+ - `payment.completed` — payment completed
830
+ - `payment.refunded` — payment refunded
1448
831
 
1449
- if (account.microdeposits) {
1450
- console.log('Microdeposits:', account.microdeposits)
1451
- }
832
+ #### Verification Events
833
+
834
+ - `verification.status.updated` — user verification status changed
835
+
836
+ #### Capability Events
837
+
838
+ - `capabilities.updated` — user capabilities changed
839
+
840
+ ### Setup
841
+
842
+ ```typescript
843
+ const webhook = await client.webhook.create({
844
+ url: 'https://my.webhook.url/spritz',
845
+ events: ['account.created', 'account.updated', 'payment.completed'],
1452
846
  })
1453
847
  ```
1454
848
 
1455
- ### Supported Token Matrix
1456
-
1457
- The following tokens are supported on each network for virtual accounts:
849
+ Webhook payloads have the following shape:
1458
850
 
1459
- - **Ethereum**: USDC, USDT, DAI, USDP, PYUSD
1460
- - **Polygon**: USDC
1461
- - **Base**: USDC
1462
- - **Arbitrum**: USDC
1463
- - **Avalanche**: USDC
1464
- - **Optimism**: USDC
1465
- - **Solana**: USDC, PYUSD
1466
- - **Tron**: USDT
851
+ ```json
852
+ {
853
+ "userId": "user-id",
854
+ "id": "resource-id",
855
+ "eventName": "event-name"
856
+ }
857
+ ```
1467
858
 
1468
- ### Complete Example
859
+ ### Management
1469
860
 
1470
861
  ```typescript
1471
- import { SpritzApiClient, Environment, PaymentNetwork } from '@spritz-finance/api-client'
862
+ // List all webhooks
863
+ const webhooks = await client.webhook.list()
1472
864
 
1473
- const client = SpritzApiClient.initialize({
1474
- environment: Environment.Production,
1475
- integrationKey: 'YOUR_INTEGRATION_KEY',
1476
- })
865
+ // Delete a webhook
866
+ await client.webhook.delete('webhook-id')
867
+ ```
1477
868
 
1478
- // Set user API key
1479
- client.setApiKey(userApiKey)
869
+ ### Security and Signing
1480
870
 
1481
- async function setupOnramp() {
1482
- // 1. Check current access
1483
- const access = await client.user.getUserAccess()
871
+ Webhook requests are signed with HMAC SHA256 using your webhook secret. The signature is sent in the `Signature` HTTP header.
1484
872
 
1485
- if (!access.capabilities.onramp.active) {
1486
- console.log('On-ramp not active. Requirements:')
873
+ #### Setting a Webhook Secret
1487
874
 
1488
- for (const req of access.capabilities.onramp.requirements) {
1489
- if (req.type === 'terms_acceptance' && req.actionUrl) {
1490
- // Direct user to accept terms
1491
- console.log('Accept terms at:', req.actionUrl)
1492
- // After acceptance, call:
1493
- // await client.onramp.acceptTermsOfService(agreementId)
1494
- }
1495
- }
875
+ ```typescript
876
+ await client.webhook.updateWebhookSecret('your-secret')
877
+ ```
1496
878
 
1497
- return false
1498
- }
879
+ #### Verifying Signatures
1499
880
 
1500
- // 2. Create virtual account
1501
- const virtualAccount = await client.virtualAccounts.create({
1502
- network: PaymentNetwork.Ethereum,
1503
- address: '0xUserWalletAddress',
1504
- token: 'USDC',
1505
- })
881
+ ```typescript
882
+ import { createHmac } from 'crypto'
1506
883
 
1507
- console.log('Virtual account created!')
1508
- console.log('Send funds to:', virtualAccount.depositInstructions)
884
+ const expected = createHmac('sha256', WEBHOOK_SECRET).update(JSON.stringify(payload)).digest('hex')
1509
885
 
1510
- return true
886
+ if (expected !== request.headers['signature']) {
887
+ throw new Error('Invalid webhook signature')
1511
888
  }
1512
-
1513
- setupOnramp().then((success) => {
1514
- if (success) {
1515
- console.log('On-ramp setup complete!')
1516
- }
1517
- })
1518
889
  ```