diff --git a/src/__tests__/resources.test.ts b/src/__tests__/resources.test.ts index 1441522..9b925cf 100644 --- a/src/__tests__/resources.test.ts +++ b/src/__tests__/resources.test.ts @@ -112,29 +112,29 @@ function lastJsonLog(): Record { const BASE = 'https://api.blindpay.com/v1/instances/in_testInstance' -describe('Receivers', () => { +describe('Customers', () => { beforeEach(setupTestEnv) afterEach(teardownTestEnv) - test('lists receivers', async () => { - mockResponse.body = { data: [{ id: 're_1', type: 'individual', email: 'a@b.com' }] } - await resources.listReceivers({ json: true }) + test('lists customers', async () => { + mockResponse.body = [{ id: 're_1', type: 'individual', email: 'a@b.com' }] + await resources.listCustomers({ json: true }) expect(lastCall().method).toBe('GET') - expect(lastCall().url).toBe(`${BASE}/receivers`) + expect(lastCall().url).toBe(`${BASE}/customers`) }) - test('fetches a receiver by id', async () => { + test('fetches a customer by id', async () => { mockResponse.body = { id: 're_xyz' } - await resources.getReceiver('re_xyz', { json: true }) + await resources.getCustomer('re_xyz', { json: true }) expect(lastCall().method).toBe('GET') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz`) }) - test('creates a receiver, splitting --name into first_name and last_name and filling defaults', async () => { + test('creates a customer, splitting --name into first_name and last_name and filling defaults', async () => { mockResponse.body = { id: 're_new', type: 'individual' } - await resources.createReceiver({ email: 'a@b.com', name: 'Jane Doe', json: true }) + await resources.createCustomer({ email: 'a@b.com', name: 'Jane Doe', json: true }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers`) + expect(lastCall().url).toBe(`${BASE}/customers`) expect(lastCall().body).toEqual({ type: 'individual', email: 'a@b.com', @@ -150,34 +150,34 @@ describe('Receivers', () => { test('updates only the fields explicitly passed via flags', async () => { mockResponse.body = { id: 're_xyz' } - await resources.updateReceiver('re_xyz', { email: 'new@b.com', json: true }) + await resources.updateCustomer('re_xyz', { email: 'new@b.com', json: true }) expect(lastCall().method).toBe('PUT') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz`) expect(lastCall().body).toEqual({ email: 'new@b.com' }) }) - test('deletes a receiver by id', async () => { + test('deletes a customer by id', async () => { mockResponse.body = { success: true } - await resources.deleteReceiver('re_xyz', { json: true }) + await resources.deleteCustomer('re_xyz', { json: true }) expect(lastCall().method).toBe('DELETE') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz`) }) - test('fetches receiver limits', async () => { + test('fetches customer limits', async () => { mockResponse.body = { per_transaction: 100 } - await resources.getReceiverLimits('re_xyz', { json: true }) - expect(lastCall().url).toBe(`${BASE}/limits/receivers/re_xyz`) + await resources.getCustomerLimits('re_xyz', { json: true }) + expect(lastCall().url).toBe(`${BASE}/limits/customers/re_xyz`) }) - test('fetches receiver limit-increase requests', async () => { + test('fetches customer limit-increase requests', async () => { mockResponse.body = [] - await resources.getReceiverLimitsIncreaseRequests('re_xyz', { json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/limit-increase`) + await resources.getCustomerLimitIncreaseRequests('re_xyz', { json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/limit-increase`) }) test('creates a limit-increase request with monetary fields parsed as integers', async () => { mockResponse.body = { id: 'rl_new' } - await resources.createReceiverLimitIncrease('re_xyz', { + await resources.createCustomerLimitIncrease('re_xyz', { perTransaction: '100000', daily: '200000', monthly: '1000000', @@ -186,7 +186,7 @@ describe('Receivers', () => { json: true, }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/limit-increase`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/limit-increase`) expect(lastCall().body).toEqual({ per_transaction: 100000, daily: 200000, @@ -201,22 +201,22 @@ describe('Bank Accounts', () => { beforeEach(setupTestEnv) afterEach(teardownTestEnv) - test('lists bank accounts for a receiver', async () => { + test('lists bank accounts for a customer', async () => { mockResponse.body = [] - await resources.listBankAccounts({ receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/bank-accounts`) + await resources.listBankAccounts({ customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts`) }) test('fetches a bank account by id', async () => { mockResponse.body = { id: 'ba_1' } - await resources.getBankAccount('ba_1', { receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/bank-accounts/ba_1`) + await resources.getBankAccount('ba_1', { customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts/ba_1`) }) test('creates a bank account, snake_casing keys and defaulting unset fields to null', async () => { mockResponse.body = { id: 'ba_new', type: 'ach' } await resources.createBankAccount({ - receiverId: 're_xyz', + customerId: 're_xyz', type: 'ach', beneficiaryName: 'Jane', routingNumber: '021000021', @@ -224,7 +224,7 @@ describe('Bank Accounts', () => { json: true, }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/bank-accounts`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts`) expect(lastCall().body).toEqual({ type: 'ach', name: 'CLI Bank Account', @@ -236,15 +236,56 @@ describe('Bank Accounts', () => { account_type: null, account_class: null, country: null, - swift_ifsc_branch_code: null, + }) + }) + + test('creates a sepa bank account with the full sepa_beneficiary_* field set', async () => { + mockResponse.body = { id: 'ba_sepa', type: 'sepa' } + await resources.createBankAccount({ + customerId: 're_xyz', + type: 'sepa', + accountClass: 'individual', + sepaIban: 'DE89370400440532013000', + sepaBeneficiaryBic: 'COBADEFFXXX', + sepaBeneficiaryLegalName: 'Jane Doe', + sepaBeneficiaryAddressLine1: 'Hauptstrasse 1', + sepaBeneficiaryAddressLine2: 'Apt 2', + sepaBeneficiaryCity: 'Berlin', + sepaBeneficiaryStateProvinceRegion: 'BE', + sepaBeneficiaryPostalCode: '10115', + sepaBeneficiaryCountry: 'DE', + json: true, + }) + expect(lastCall().method).toBe('POST') + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts`) + expect(lastCall().body).toEqual({ + type: 'sepa', + name: 'CLI Bank Account', + recipient_relationship: null, + pix_key: null, + beneficiary_name: null, + routing_number: null, + account_number: null, + account_type: null, + account_class: 'individual', + country: null, + sepa_iban: 'DE89370400440532013000', + sepa_beneficiary_bic: 'COBADEFFXXX', + sepa_beneficiary_legal_name: 'Jane Doe', + sepa_beneficiary_address_line_1: 'Hauptstrasse 1', + sepa_beneficiary_address_line_2: 'Apt 2', + sepa_beneficiary_city: 'Berlin', + sepa_beneficiary_state_province_region: 'BE', + sepa_beneficiary_postal_code: '10115', + sepa_beneficiary_country: 'DE', }) }) test('deletes a bank account', async () => { mockResponse.body = { success: true } - await resources.deleteBankAccount('ba_1', { receiverId: 're_xyz', json: true }) + await resources.deleteBankAccount('ba_1', { customerId: 're_xyz', json: true }) expect(lastCall().method).toBe('DELETE') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/bank-accounts/ba_1`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts/ba_1`) }) }) @@ -252,28 +293,28 @@ describe('Blockchain Wallets', () => { beforeEach(setupTestEnv) afterEach(teardownTestEnv) - test('lists blockchain wallets for a receiver', async () => { + test('lists blockchain wallets for a customer', async () => { mockResponse.body = [] - await resources.listBlockchainWallets({ receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/blockchain-wallets`) + await resources.listBlockchainWallets({ customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/blockchain-wallets`) }) test('fetches a blockchain wallet by id', async () => { mockResponse.body = { id: 'bw_1' } - await resources.getBlockchainWallet('bw_1', { receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/blockchain-wallets/bw_1`) + await resources.getBlockchainWallet('bw_1', { customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/blockchain-wallets/bw_1`) }) - test('creates a blockchain wallet for a receiver', async () => { + test('creates a blockchain wallet for a customer', async () => { mockResponse.body = { id: 'bw_new', network: 'base' } await resources.createBlockchainWallet({ - receiverId: 're_xyz', + customerId: 're_xyz', address: '0xabc', network: 'base', json: true, }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/blockchain-wallets`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/blockchain-wallets`) expect(lastCall().body).toEqual({ address: '0xabc', network: 'base', @@ -284,9 +325,9 @@ describe('Blockchain Wallets', () => { test('deletes a blockchain wallet', async () => { mockResponse.body = { success: true } - await resources.deleteBlockchainWallet('bw_1', { receiverId: 're_xyz', json: true }) + await resources.deleteBlockchainWallet('bw_1', { customerId: 're_xyz', json: true }) expect(lastCall().method).toBe('DELETE') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/blockchain-wallets/bw_1`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/blockchain-wallets/bw_1`) }) }) @@ -515,17 +556,17 @@ describe('Virtual Accounts', () => { beforeEach(setupTestEnv) afterEach(teardownTestEnv) - test('lists virtual accounts for a receiver', async () => { + test('lists virtual accounts for a customer', async () => { mockResponse.body = [] - await resources.listVirtualAccounts({ receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/virtual-accounts`) + await resources.listVirtualAccounts({ customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/virtual-accounts`) }) - test('creates a virtual account for a receiver', async () => { + test('creates a virtual account for a customer', async () => { mockResponse.body = { id: 'va_new' } - await resources.createVirtualAccount({ receiverId: 're_xyz', blockchainWalletId: 'bw_1', json: true }) + await resources.createVirtualAccount({ customerId: 're_xyz', blockchainWalletId: 'bw_1', json: true }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/virtual-accounts`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/virtual-accounts`) expect(lastCall().body).toEqual({ blockchain_wallet_id: 'bw_1' }) }) }) @@ -536,8 +577,8 @@ describe('Offramp Wallets', () => { test('lists offramp wallets for a bank account', async () => { mockResponse.body = [] - await resources.listOfframpWallets({ receiverId: 're_xyz', bankAccountId: 'ba_1', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/bank-accounts/ba_1/offramp-wallets`) + await resources.listOfframpWallets({ customerId: 're_xyz', bankAccountId: 'ba_1', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/bank-accounts/ba_1/offramp-wallets`) }) }) @@ -587,49 +628,49 @@ describe('Wallets (custodial)', () => { beforeEach(setupTestEnv) afterEach(teardownTestEnv) - test('lists custodial wallets for a receiver', async () => { + test('lists custodial wallets for a customer', async () => { mockResponse.body = [] - await resources.listWallets({ receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/wallets`) + await resources.listWallets({ customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/wallets`) }) test('fetches a custodial wallet by id', async () => { mockResponse.body = { id: 'bl_1' } - await resources.getWallet('bl_1', { receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/wallets/bl_1`) + await resources.getWallet('bl_1', { customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/wallets/bl_1`) }) test('fetches a custodial wallet balance', async () => { mockResponse.body = { USDC: { amount: 0 } } - await resources.getWalletBalance('bl_1', { receiverId: 're_xyz', json: true }) - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/wallets/bl_1/balance`) + await resources.getWalletBalance('bl_1', { customerId: 're_xyz', json: true }) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/wallets/bl_1/balance`) }) test('creates a custodial wallet with --external-id', async () => { mockResponse.body = { id: 'bl_new', network: 'polygon' } await resources.createWallet({ - receiverId: 're_xyz', + customerId: 're_xyz', network: 'polygon', name: 'Main', externalId: 'ext-1', json: true, }) expect(lastCall().method).toBe('POST') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/wallets`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/wallets`) expect(lastCall().body).toEqual({ network: 'polygon', name: 'Main', external_id: 'ext-1' }) }) test('omits external_id from the body when --external-id is not passed', async () => { mockResponse.body = { id: 'bl_new', network: 'polygon' } - await resources.createWallet({ receiverId: 're_xyz', network: 'polygon', name: 'Main', json: true }) + await resources.createWallet({ customerId: 're_xyz', network: 'polygon', name: 'Main', json: true }) expect(lastCall().body).toEqual({ network: 'polygon', name: 'Main' }) }) test('deletes a custodial wallet', async () => { mockResponse.body = { success: true } - await resources.deleteWallet('bl_1', { receiverId: 're_xyz', json: true }) + await resources.deleteWallet('bl_1', { customerId: 're_xyz', json: true }) expect(lastCall().method).toBe('DELETE') - expect(lastCall().url).toBe(`${BASE}/receivers/re_xyz/wallets/bl_1`) + expect(lastCall().url).toBe(`${BASE}/customers/re_xyz/wallets/bl_1`) }) }) @@ -732,7 +773,7 @@ describe('Terms of Service', () => { mockResponse.body = { url: 'https://app.blindpay.com/e/terms-of-service?...' } await resources.initiateTos({ idempotencyKey: 'idem-1', - receiverId: 're_xyz', + customerId: 're_xyz', redirectUrl: 'https://example.com', json: true, }) @@ -785,13 +826,13 @@ describe('Error handling', () => { afterEach(teardownTestEnv) test('exits with code 2 and emits a JSON error payload on a non-2xx response', async () => { - mockResponse = { status: 404, body: { message: 'receiver not found', errors: [] } } - await expect(resources.getReceiver('re_xyz', { json: true })).rejects.toThrow('__test_exit__2') + mockResponse = { status: 404, body: { message: 'customer not found', errors: [] } } + await expect(resources.getCustomer('re_xyz', { json: true })).rejects.toThrow('__test_exit__2') expect(lastJsonLog()).toMatchObject({ error: true, exitCode: 2, statusCode: 404, - message: 'receiver not found', + message: 'customer not found', }) }) @@ -803,7 +844,7 @@ describe('Error handling', () => { errors: [{ path: ['email'], message: 'required' }], }, } - await expect(resources.createReceiver({ email: 'x', json: true })).rejects.toThrow('__test_exit__2') + await expect(resources.createCustomer({ email: 'x', json: true })).rejects.toThrow('__test_exit__2') expect(lastJsonLog()).toMatchObject({ error: true, exitCode: 2, diff --git a/src/commands/resources.ts b/src/commands/resources.ts index 148b934..4572f20 100644 --- a/src/commands/resources.ts +++ b/src/commands/resources.ts @@ -67,11 +67,11 @@ function extractList(res: any): any[] { return [] } -// Receivers -export async function listReceivers(options: { json: boolean }) { +// Customers +export async function listCustomers(options: { json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers`) const list = extractList(res) const display = list.map((r: any) => ({ id: r.id, @@ -88,18 +88,18 @@ export async function listReceivers(options: { json: boolean }) { } } -export async function getReceiver(id: string, options: { json: boolean }) { +export async function getCustomer(id: string, options: { json: boolean }) { try { const ctx = resolveContext() - const receiver = await apiGet(ctx, `${instancePath(ctx)}/receivers/${id}`) - printResult(receiver, options.json) + const customer = await apiGet(ctx, `${instancePath(ctx)}/customers/${id}`) + printResult(customer, options.json) } catch (e) { handleApiError(e, options.json) } } -export async function createReceiver(options: { +export async function createCustomer(options: { email: string type?: string name?: string @@ -138,20 +138,20 @@ export async function createReceiver(options: { external_id: options.externalId ?? null, kyc_status: options.kycStatus ?? 'approved', } - const receiver = await apiPost<{ id: string, type: string }>(ctx, `${instancePath(ctx)}/receivers`, body) + const customer = await apiPost<{ id: string, type: string }>(ctx, `${instancePath(ctx)}/customers`, body) const displayName = body.type === 'business' ? (body.legal_name || '—') : [body.first_name, body.last_name].filter(Boolean).join(' ').trim() || '—' - clack.log.success(`Created receiver ${receiver.id} (${receiver.type}, ${displayName})`) + clack.log.success(`Created customer ${customer.id} (${customer.type}, ${displayName})`) if (options.json) - console.log(formatOutput(receiver, true)) + console.log(formatOutput(customer, true)) } catch (e) { handleApiError(e, options.json) } } -export async function updateReceiver( +export async function updateCustomer( id: string, options: { name?: string @@ -193,23 +193,23 @@ export async function updateReceiver( if (Object.keys(body).length === 0) { exitWithError('Provide at least one field to update (e.g. --name, --kyc-status)', 1, options.json) } - const receiver = await apiPut>(ctx, `${instancePath(ctx)}/receivers/${id}`, body) - clack.log.success(`Updated receiver ${id}`) + const customer = await apiPut>(ctx, `${instancePath(ctx)}/customers/${id}`, body) + clack.log.success(`Updated customer ${id}`) if (options.json) - console.log(formatOutput(receiver, true)) + console.log(formatOutput(customer, true)) else - console.log(formatOutput(receiver, false)) + console.log(formatOutput(customer, false)) } catch (e) { handleApiError(e, options.json) } } -export async function deleteReceiver(id: string, options: { json?: boolean } = {}) { +export async function deleteCustomer(id: string, options: { json?: boolean } = {}) { try { const ctx = resolveContext() - await apiDelete(ctx, `${instancePath(ctx)}/receivers/${id}`) - clack.log.success(`Deleted receiver ${id}`) + await apiDelete(ctx, `${instancePath(ctx)}/customers/${id}`) + clack.log.success(`Deleted customer ${id}`) } catch (e) { handleApiError(e, options.json) @@ -217,10 +217,10 @@ export async function deleteReceiver(id: string, options: { json?: boolean } = { } // Bank Accounts -export async function listBankAccounts(options: { receiverId: string, json: boolean }) { +export async function listBankAccounts(options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/bank-accounts`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/bank-accounts`) const list = extractList(res) const display = list.map((a: any) => ({ id: a.id, type: a.type, name: a.name, status: a.status, country: a.country })) printResult(options.json ? list : display, options.json, ['id', 'type', 'name', 'status', 'country']) @@ -230,10 +230,10 @@ export async function listBankAccounts(options: { receiverId: string, json: bool } } -export async function getBankAccount(id: string, options: { receiverId: string, json: boolean }) { +export async function getBankAccount(id: string, options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const account = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/bank-accounts/${id}`) + const account = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/bank-accounts/${id}`) printResult(account, options.json) } catch (e) { @@ -242,7 +242,7 @@ export async function getBankAccount(id: string, options: { receiverId: string, } export async function createBankAccount(options: { - receiverId: string + customerId: string type?: string name?: string recipientRelationship?: string @@ -253,12 +253,20 @@ export async function createBankAccount(options: { accountType?: string accountClass?: string country?: string - swiftIfscBranchCode?: string + sepaIban?: string + sepaBeneficiaryBic?: string + sepaBeneficiaryLegalName?: string + sepaBeneficiaryAddressLine1?: string + sepaBeneficiaryAddressLine2?: string + sepaBeneficiaryCity?: string + sepaBeneficiaryStateProvinceRegion?: string + sepaBeneficiaryPostalCode?: string + sepaBeneficiaryCountry?: string json: boolean }) { try { const ctx = resolveContext() - const body = { + const body: Record = { type: options.type || 'ach', name: options.name || 'CLI Bank Account', recipient_relationship: options.recipientRelationship ?? null, @@ -269,9 +277,17 @@ export async function createBankAccount(options: { account_type: options.accountType ?? null, account_class: options.accountClass ?? null, country: options.country ?? null, - swift_ifsc_branch_code: options.swiftIfscBranchCode ?? null, } - const ba = await apiPost<{ id: string, type: string }>(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/bank-accounts`, body) + if (options.sepaIban) body.sepa_iban = options.sepaIban + if (options.sepaBeneficiaryBic) body.sepa_beneficiary_bic = options.sepaBeneficiaryBic + if (options.sepaBeneficiaryLegalName) body.sepa_beneficiary_legal_name = options.sepaBeneficiaryLegalName + if (options.sepaBeneficiaryAddressLine1) body.sepa_beneficiary_address_line_1 = options.sepaBeneficiaryAddressLine1 + if (options.sepaBeneficiaryAddressLine2) body.sepa_beneficiary_address_line_2 = options.sepaBeneficiaryAddressLine2 + if (options.sepaBeneficiaryCity) body.sepa_beneficiary_city = options.sepaBeneficiaryCity + if (options.sepaBeneficiaryStateProvinceRegion) body.sepa_beneficiary_state_province_region = options.sepaBeneficiaryStateProvinceRegion + if (options.sepaBeneficiaryPostalCode) body.sepa_beneficiary_postal_code = options.sepaBeneficiaryPostalCode + if (options.sepaBeneficiaryCountry) body.sepa_beneficiary_country = options.sepaBeneficiaryCountry + const ba = await apiPost<{ id: string, type: string }>(ctx, `${instancePath(ctx)}/customers/${options.customerId}/bank-accounts`, body) clack.log.success(`Created bank account ${ba.id} (${ba.type})`) if (options.json) console.log(formatOutput(ba, true)) @@ -281,10 +297,10 @@ export async function createBankAccount(options: { } } -export async function deleteBankAccount(id: string, options: { receiverId: string, json?: boolean }) { +export async function deleteBankAccount(id: string, options: { customerId: string, json?: boolean }) { try { const ctx = resolveContext() - await apiDelete(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/bank-accounts/${id}`) + await apiDelete(ctx, `${instancePath(ctx)}/customers/${options.customerId}/bank-accounts/${id}`) clack.log.success(`Deleted bank account ${id}`) } catch (e) { @@ -293,10 +309,10 @@ export async function deleteBankAccount(id: string, options: { receiverId: strin } // Blockchain Wallets -export async function listBlockchainWallets(options: { receiverId: string, json: boolean }) { +export async function listBlockchainWallets(options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/blockchain-wallets`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/blockchain-wallets`) const list = extractList(res) const display = list.map((w: any) => ({ id: w.id, address: truncate(w.address, 20), network: w.network })) printResult(options.json ? list : display, options.json, ['id', 'address', 'network']) @@ -306,10 +322,10 @@ export async function listBlockchainWallets(options: { receiverId: string, json: } } -export async function getBlockchainWallet(id: string, options: { receiverId: string, json: boolean }) { +export async function getBlockchainWallet(id: string, options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const wallet = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/blockchain-wallets/${id}`) + const wallet = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/blockchain-wallets/${id}`) printResult(wallet, options.json) } catch (e) { @@ -318,7 +334,7 @@ export async function getBlockchainWallet(id: string, options: { receiverId: str } export async function createBlockchainWallet(options: { - receiverId: string + customerId: string address: string network?: string name?: string @@ -333,7 +349,7 @@ export async function createBlockchainWallet(options: { name: options.name || 'CLI Blockchain Wallet', external_id: options.externalId ?? null, } - const wallet = await apiPost<{ id: string, network: string }>(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/blockchain-wallets`, body) + const wallet = await apiPost<{ id: string, network: string }>(ctx, `${instancePath(ctx)}/customers/${options.customerId}/blockchain-wallets`, body) clack.log.success(`Created blockchain wallet ${wallet.id} (${wallet.network})`) if (options.json) console.log(formatOutput(wallet, true)) @@ -343,10 +359,10 @@ export async function createBlockchainWallet(options: { } } -export async function deleteBlockchainWallet(id: string, options: { receiverId: string, json?: boolean }) { +export async function deleteBlockchainWallet(id: string, options: { customerId: string, json?: boolean }) { try { const ctx = resolveContext() - await apiDelete(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/blockchain-wallets/${id}`) + await apiDelete(ctx, `${instancePath(ctx)}/customers/${options.customerId}/blockchain-wallets/${id}`) clack.log.success(`Deleted blockchain wallet ${id}`) } catch (e) { @@ -661,10 +677,10 @@ export async function deleteApiKey(id: string, options: { json?: boolean } = {}) } // Virtual Accounts -export async function listVirtualAccounts(options: { receiverId: string, json: boolean }) { +export async function listVirtualAccounts(options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/virtual-accounts`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/virtual-accounts`) const list = extractList(res) const display = list.map((a: any) => ({ id: a.id, account_number: a.account_number, routing_number: a.routing_number, kyc_status: a.kyc_status })) printResult(options.json ? list : display, options.json, ['id', 'account_number', 'routing_number', 'kyc_status']) @@ -674,10 +690,10 @@ export async function listVirtualAccounts(options: { receiverId: string, json: b } } -export async function createVirtualAccount(options: { receiverId: string, blockchainWalletId: string, json: boolean }) { +export async function createVirtualAccount(options: { customerId: string, blockchainWalletId: string, json: boolean }) { try { const ctx = resolveContext() - const account = await apiPost<{ id: string }>(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/virtual-accounts`, { blockchain_wallet_id: options.blockchainWalletId }) + const account = await apiPost<{ id: string }>(ctx, `${instancePath(ctx)}/customers/${options.customerId}/virtual-accounts`, { blockchain_wallet_id: options.blockchainWalletId }) clack.log.success(`Created virtual account ${account.id}`) if (options.json) console.log(formatOutput(account, true)) @@ -688,10 +704,10 @@ export async function createVirtualAccount(options: { receiverId: string, blockc } // Offramp Wallets -export async function listOfframpWallets(options: { receiverId: string, bankAccountId: string, json: boolean }) { +export async function listOfframpWallets(options: { customerId: string, bankAccountId: string, json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/bank-accounts/${options.bankAccountId}/offramp-wallets`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/bank-accounts/${options.bankAccountId}/offramp-wallets`) const list = extractList(res) const display = list.map((w: any) => ({ id: w.id, address: truncate(w.address, 20), network: w.network })) printResult(options.json ? list : display, options.json, ['id', 'address', 'network']) @@ -748,11 +764,11 @@ export async function updateInstance(options: { } } -// Receiver Limits -export async function getReceiverLimits(receiverId: string, options: { json: boolean }) { +// Customer Limits +export async function getCustomerLimits(customerId: string, options: { json: boolean }) { try { const ctx = resolveContext() - const limits = await apiGet(ctx, `${instancePath(ctx)}/limits/receivers/${receiverId}`) + const limits = await apiGet(ctx, `${instancePath(ctx)}/limits/customers/${customerId}`) printResult(limits, options.json) } catch (e) { @@ -760,20 +776,20 @@ export async function getReceiverLimits(receiverId: string, options: { json: boo } } -export async function getReceiverLimitsIncreaseRequests(receiverId: string, options: { json: boolean }) { +export async function getCustomerLimitIncreaseRequests(customerId: string, options: { json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${receiverId}/limit-increase`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${customerId}/limit-increase`) const list = extractList(res) - printResult(list, options.json, ['id', 'status', 'per_transaction', 'daily', 'monthly', 'created_at']) + printResult(list, options.json) } catch (e) { handleApiError(e, options.json) } } -export async function createReceiverLimitIncrease( - receiverId: string, +export async function createCustomerLimitIncrease( + customerId: string, options: { perTransaction: string daily: string @@ -792,7 +808,7 @@ export async function createReceiverLimitIncrease( supporting_document_type: options.supportingDocumentType, supporting_document_file: options.supportingDocumentFile, } - const res = await apiPost<{ id: string }>(ctx, `${instancePath(ctx)}/receivers/${receiverId}/limit-increase`, body) + const res = await apiPost<{ id: string }>(ctx, `${instancePath(ctx)}/customers/${customerId}/limit-increase`, body) clack.log.success(`Created limit increase request ${res.id}`) printResult(res, options.json) } @@ -842,10 +858,10 @@ export async function getAvailableBankDetails(options: { rail: string, json: boo } // Wallets (custodial, distinct from blockchain_wallets) -export async function listWallets(options: { receiverId: string, json: boolean }) { +export async function listWallets(options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const res = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/wallets`) + const res = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/wallets`) const list = extractList(res) printResult(list, options.json, ['id', 'name', 'network', 'address']) } @@ -854,10 +870,10 @@ export async function listWallets(options: { receiverId: string, json: boolean } } } -export async function getWallet(id: string, options: { receiverId: string, json: boolean }) { +export async function getWallet(id: string, options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const wallet = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/wallets/${id}`) + const wallet = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/wallets/${id}`) printResult(wallet, options.json) } catch (e) { @@ -865,10 +881,10 @@ export async function getWallet(id: string, options: { receiverId: string, json: } } -export async function getWalletBalance(id: string, options: { receiverId: string, json: boolean }) { +export async function getWalletBalance(id: string, options: { customerId: string, json: boolean }) { try { const ctx = resolveContext() - const balance = await apiGet(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/wallets/${id}/balance`) + const balance = await apiGet(ctx, `${instancePath(ctx)}/customers/${options.customerId}/wallets/${id}/balance`) printResult(balance, options.json) } catch (e) { @@ -877,7 +893,7 @@ export async function getWalletBalance(id: string, options: { receiverId: string } export async function createWallet(options: { - receiverId: string + customerId: string network: string name: string externalId?: string @@ -890,7 +906,7 @@ export async function createWallet(options: { name: options.name, } if (options.externalId !== undefined) body.external_id = options.externalId - const wallet = await apiPost<{ id: string, network: string }>(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/wallets`, body) + const wallet = await apiPost<{ id: string, network: string }>(ctx, `${instancePath(ctx)}/customers/${options.customerId}/wallets`, body) clack.log.success(`Created wallet ${wallet.id} (${wallet.network})`) printResult(wallet, options.json) } @@ -899,10 +915,10 @@ export async function createWallet(options: { } } -export async function deleteWallet(id: string, options: { receiverId: string, json?: boolean }) { +export async function deleteWallet(id: string, options: { customerId: string, json?: boolean }) { try { const ctx = resolveContext() - await apiDelete(ctx, `${instancePath(ctx)}/receivers/${options.receiverId}/wallets/${id}`) + await apiDelete(ctx, `${instancePath(ctx)}/customers/${options.customerId}/wallets/${id}`) clack.log.success(`Deleted wallet ${id}`) } catch (e) { @@ -1006,11 +1022,13 @@ export async function getInstanceFees(options: { json: boolean }) { } // Terms of Service -export async function initiateTos(options: { idempotencyKey: string, receiverId?: string, redirectUrl?: string, json: boolean }) { +export async function initiateTos(options: { idempotencyKey: string, customerId?: string, redirectUrl?: string, json: boolean }) { try { const ctx = resolveContext() const body: Record = { idempotency_key: options.idempotencyKey } - if (options.receiverId !== undefined) body.receiver_id = options.receiverId + // The TOS endpoint's body still uses receiver_id on the wire (matches node + the Swift SDK); + // keep the clean customerId option but map it to receiver_id. Drop once the API accepts customer_id. + if (options.customerId !== undefined) body.receiver_id = options.customerId if (options.redirectUrl !== undefined) body.redirect_url = options.redirectUrl const res = await apiPost<{ url: string }>(ctx, `/v1/e/instances/${ctx.instanceId}/tos`, body) if (!options.json) clack.log.success(`Open this URL to accept the Terms of Service:\n${res.url}`) diff --git a/src/commands/schema.ts b/src/commands/schema.ts index 4a2781d..f2da478 100644 --- a/src/commands/schema.ts +++ b/src/commands/schema.ts @@ -19,12 +19,12 @@ interface ResourceSchema { const schemas: ResourceSchema[] = [ { - resource: 'receivers', + resource: 'customers', commands: ['list', 'get', 'create', 'update', 'delete'], create: { fields: [ - { name: 'email', type: 'string', required: true, description: 'Receiver email address' }, - { name: 'type', type: 'string', required: false, description: 'Receiver type', default: 'individual', enum: ['individual', 'business'] }, + { name: 'email', type: 'string', required: true, description: 'Customer email address' }, + { name: 'type', type: 'string', required: false, description: 'Customer type', default: 'individual', enum: ['individual', 'business'] }, { name: 'name', type: 'string', required: false, description: 'Full name (individual); auto-splits into first_name and last_name' }, { name: 'first_name', type: 'string', required: false, description: 'First name (individual)' }, { name: 'last_name', type: 'string', required: false, description: 'Last name (individual)' }, @@ -41,7 +41,7 @@ const schemas: ResourceSchema[] = [ { name: 'first_name', type: 'string', required: false, description: 'First name (individual)' }, { name: 'last_name', type: 'string', required: false, description: 'Last name (individual)' }, { name: 'legal_name', type: 'string', required: false, description: 'Legal name (business)' }, - { name: 'email', type: 'string', required: false, description: 'Receiver email address' }, + { name: 'email', type: 'string', required: false, description: 'Customer email address' }, { name: 'country', type: 'string', required: false, description: 'ISO 3166 country code' }, { name: 'kyc_status', type: 'string', required: false, description: 'KYC verification status', enum: ['verifying', 'approved', 'rejected', 'deprecated'] }, ], @@ -52,7 +52,7 @@ const schemas: ResourceSchema[] = [ commands: ['list', 'get', 'create', 'delete'], create: { fields: [ - { name: 'receiver_id', type: 'string', required: true, description: 'Receiver ID that owns this bank account' }, + { name: 'customer_id', type: 'string', required: true, description: 'Customer ID that owns this bank account' }, { name: 'type', type: 'string', required: false, description: 'Bank account type / payment rail', default: 'ach', enum: Object.keys(bankDetailFields) }, { name: 'name', type: 'string', required: false, description: 'Account display name', default: 'CLI Bank Account' }, { name: 'beneficiary_name', type: 'string', required: false, description: 'Beneficiary name on the account' }, @@ -71,7 +71,7 @@ const schemas: ResourceSchema[] = [ commands: ['list', 'get', 'create', 'delete'], create: { fields: [ - { name: 'receiver_id', type: 'string', required: true, description: 'Receiver ID that owns this wallet' }, + { name: 'customer_id', type: 'string', required: true, description: 'Customer ID that owns this wallet' }, { name: 'address', type: 'string', required: true, description: 'Blockchain wallet address' }, { name: 'network', type: 'string', required: false, description: 'Blockchain network', default: 'base', enum: ['base', 'ethereum', 'polygon', 'solana', 'stellar', 'arbitrum', 'optimism'] }, { name: 'external_id', type: 'string', required: false, description: 'External reference ID' }, @@ -162,7 +162,7 @@ const schemas: ResourceSchema[] = [ commands: ['list', 'create'], create: { fields: [ - { name: 'receiver_id', type: 'string', required: true, description: 'Receiver ID' }, + { name: 'customer_id', type: 'string', required: true, description: 'Customer ID' }, { name: 'blockchain_wallet_id', type: 'string', required: true, description: 'Blockchain wallet ID' }, ], }, diff --git a/src/index.ts b/src/index.ts index 735694d..f78a8fc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,13 +3,14 @@ import { Command } from 'commander' import * as clack from '@clack/prompts' import { listSchemas, getSchema } from './commands/schema' import { - listReceivers, - getReceiver, - createReceiver, - updateReceiver, - deleteReceiver, - getReceiverLimits, - getReceiverLimitsIncreaseRequests, + listCustomers, + getCustomer, + createCustomer, + updateCustomer, + deleteCustomer, + getCustomerLimits, + getCustomerLimitIncreaseRequests, + createCustomerLimitIncrease, listBankAccounts, getBankAccount, createBankAccount, @@ -44,7 +45,6 @@ import { updateInstance, listAvailableRails, getAvailableBankDetails, - createReceiverLimitIncrease, listWallets, getWallet, getWalletBalance, @@ -66,12 +66,12 @@ const program = new Command() program .name('blindpay') - .description('Blindpay CLI — manage receivers, bank accounts, payouts, payins, and more from the terminal.') + .description('Blindpay CLI — manage customers, bank accounts, payouts, payins, and more from the terminal.') .version(CLI_VERSION) .addHelpText('after', ` Examples: $ blindpay config set --api-key --instance-id - $ blindpay receivers list --json + $ blindpay customers list --json $ blindpay payouts list --status processing $ blindpay available rails @@ -135,34 +135,34 @@ configCmd .description('Print config file path') .action(() => console.log(getConfigPath())) -// ── Receivers ─────────────────────────────────────────────────────────── -const receivers = program.command('receivers').description('Manage receivers') +// ── Customers ─────────────────────────────────────────────────────────── +const customers = program.command('customers').description('Manage customers') .addHelpText('after', ` Examples: - $ blindpay receivers list - $ blindpay receivers list --json - $ blindpay receivers get - $ blindpay receivers create --email user@example.com --name "John Doe" --country US - $ blindpay receivers create --type business --email biz@co.com --legal-name "Acme Inc" - $ blindpay receivers update --kyc-status approved - $ blindpay receivers delete `) - -receivers + $ blindpay customers list + $ blindpay customers list --json + $ blindpay customers get + $ blindpay customers create --email user@example.com --name "John Doe" --country US + $ blindpay customers create --type business --email biz@co.com --legal-name "Acme Inc" + $ blindpay customers update --kyc-status approved + $ blindpay customers delete `) + +customers .command('list') - .description('List all receivers') + .description('List all customers') .option('--json', 'Output as JSON', false) - .action(opts => listReceivers(opts)) + .action(opts => listCustomers(opts)) -receivers +customers .command('get ') - .description('Get a receiver by ID') + .description('Get a customer by ID') .option('--json', 'Output as JSON', false) - .action((id, opts) => getReceiver(id, opts)) + .action((id, opts) => getCustomer(id, opts)) -receivers +customers .command('create') - .description('Create a new receiver') - .requiredOption('--email ', 'Receiver email') + .description('Create a new customer') + .requiredOption('--email ', 'Customer email') .option('--type ', 'individual or business', 'individual') .option('--name ', 'Full name (individual); splits into first_name and last_name') .option('--first-name ', 'First name (individual)') @@ -173,79 +173,79 @@ receivers .option('--external-id ', 'External ID') .option('--kyc-status ', 'KYC status (verifying, approved, rejected, deprecated)', 'approved') .option('--json', 'Output as JSON', false) - .action(opts => createReceiver(opts)) + .action(opts => createCustomer(opts)) -receivers +customers .command('update ') - .description('Update a receiver') + .description('Update a customer') .option('--name ', 'Full name (individual); splits into first_name and last_name') .option('--first-name ', 'First name (individual)') .option('--last-name ', 'Last name (individual)') .option('--legal-name ', 'Legal name (business)') - .option('--email ', 'Receiver email') + .option('--email ', 'Customer email') .option('--country ', 'ISO 3166 country code') .option('--kyc-status ', 'KYC status (verifying, approved, rejected, deprecated)') .option('--json', 'Output as JSON', false) - .action((id, opts) => updateReceiver(id, opts)) + .action((id, opts) => updateCustomer(id, opts)) -receivers +customers .command('delete ') - .description('Delete a receiver') + .description('Delete a customer') .option('--json', 'Output as JSON', false) - .action((id, opts) => deleteReceiver(id, opts)) + .action((id, opts) => deleteCustomer(id, opts)) -receivers +customers .command('limits ') - .description('Get receiver limits') + .description('Get customer limits') .option('--json', 'Output as JSON', false) - .action((id, opts) => getReceiverLimits(id, opts)) + .action((id, opts) => getCustomerLimits(id, opts)) -receivers +customers .command('limits_increase_requests ') - .description('Get receiver limit-increase requests') + .description('Get customer limit-increase requests') .option('--json', 'Output as JSON', false) - .action((id, opts) => getReceiverLimitsIncreaseRequests(id, opts)) + .action((id, opts) => getCustomerLimitIncreaseRequests(id, opts)) -receivers +customers .command('create_limit_increase ') - .description('Request a limit increase for a receiver') + .description('Request a limit increase for a customer') .requiredOption('--per-transaction ', 'Per-transaction limit in cents') .requiredOption('--daily ', 'Daily limit in cents') .requiredOption('--monthly ', 'Monthly limit in cents') - .requiredOption('--supporting-document-type ', 'Supporting document type (individual_bank_statement, individual_tax_return, individual_proof_of_income, business_bank_statement, business_financial_statements, business_tax_return)') + .requiredOption('--supporting-document-type ', 'Supporting document type') .requiredOption('--supporting-document-file ', 'Supporting document URL (upload via `blindpay upload` first)') .option('--json', 'Output as JSON', false) - .action((id, opts) => createReceiverLimitIncrease(id, opts)) + .action((id, opts) => createCustomerLimitIncrease(id, opts)) // ── Bank Accounts ─────────────────────────────────────────────────────── const bankAccounts = program.command('bank_accounts').description('Manage bank accounts') .addHelpText('after', ` Examples: - $ blindpay bank_accounts list --receiver-id - $ blindpay bank_accounts get --receiver-id - $ blindpay bank_accounts create --receiver-id --type ach --routing-number 021000021 --account-number 123456789 - $ blindpay bank_accounts create --receiver-id --type pix --pix-key user@email.com - $ blindpay bank_accounts delete --receiver-id `) + $ blindpay bank_accounts list --customer-id + $ blindpay bank_accounts get --customer-id + $ blindpay bank_accounts create --customer-id --type ach --routing-number 021000021 --account-number 123456789 + $ blindpay bank_accounts create --customer-id --type pix --pix-key user@email.com + $ blindpay bank_accounts delete --customer-id `) bankAccounts .command('list') - .description('List bank accounts for a receiver') - .requiredOption('--receiver-id ', 'Receiver ID') + .description('List bank accounts for a customer') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action(opts => listBankAccounts(opts)) bankAccounts .command('get ') .description('Get a bank account by ID') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => getBankAccount(id, opts)) bankAccounts .command('create') .description('Create a new bank account') - .requiredOption('--receiver-id ', 'Receiver ID') - .option('--type ', 'Bank account type (ach, wire, pix, etc.)', 'ach') + .requiredOption('--customer-id ', 'Customer ID') + .option('--type ', 'Bank account type (ach, wire, pix, sepa, etc.)', 'ach') .option('--name ', 'Account name') .option('--beneficiary-name ', 'Beneficiary name') .option('--routing-number ', 'Routing number') @@ -255,14 +255,22 @@ bankAccounts .option('--pix-key ', 'PIX key') .option('--recipient-relationship ', 'Recipient relationship') .option('--country ', 'Country code') - .option('--swift-ifsc-branch-code ', 'SWIFT/IFSC branch code (international_swift accounts)') + .option('--sepa-iban ', 'IBAN (sepa accounts)') + .option('--sepa-beneficiary-bic ', 'Beneficiary BIC/SWIFT code (sepa accounts)') + .option('--sepa-beneficiary-legal-name ', 'Beneficiary legal name (sepa accounts)') + .option('--sepa-beneficiary-address-line-1 ', 'Beneficiary address line 1 (sepa accounts)') + .option('--sepa-beneficiary-address-line-2 ', 'Beneficiary address line 2 (sepa accounts)') + .option('--sepa-beneficiary-city ', 'Beneficiary city (sepa accounts)') + .option('--sepa-beneficiary-state-province-region ', 'Beneficiary state/province/region (sepa accounts)') + .option('--sepa-beneficiary-postal-code ', 'Beneficiary postal code (sepa accounts)') + .option('--sepa-beneficiary-country ', 'Beneficiary country code (sepa accounts)') .option('--json', 'Output as JSON', false) .action(opts => createBankAccount(opts)) bankAccounts .command('delete ') .description('Delete a bank account') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => deleteBankAccount(id, opts)) @@ -270,29 +278,29 @@ bankAccounts const blockchainWallets = program.command('blockchain_wallets').description('Manage blockchain wallets') .addHelpText('after', ` Examples: - $ blindpay blockchain_wallets list --receiver-id - $ blindpay blockchain_wallets get --receiver-id - $ blindpay blockchain_wallets create --receiver-id --address 0x... --network base - $ blindpay blockchain_wallets delete --receiver-id `) + $ blindpay blockchain_wallets list --customer-id + $ blindpay blockchain_wallets get --customer-id + $ blindpay blockchain_wallets create --customer-id --address 0x... --network base + $ blindpay blockchain_wallets delete --customer-id `) blockchainWallets .command('list') - .description('List blockchain wallets for a receiver') - .requiredOption('--receiver-id ', 'Receiver ID') + .description('List blockchain wallets for a customer') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action(opts => listBlockchainWallets(opts)) blockchainWallets .command('get ') .description('Get a blockchain wallet by ID') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => getBlockchainWallet(id, opts)) blockchainWallets .command('create') .description('Create a new blockchain wallet') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .requiredOption('--address
', 'Wallet address') .option('--network ', 'Blockchain network', 'base') .option('--name ', 'Wallet name') @@ -303,7 +311,7 @@ blockchainWallets blockchainWallets .command('delete ') .description('Delete a blockchain wallet') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => deleteBlockchainWallet(id, opts)) @@ -508,20 +516,20 @@ apiKeys const virtualAccounts = program.command('virtual_accounts').description('Manage virtual accounts') .addHelpText('after', ` Examples: - $ blindpay virtual_accounts list --receiver-id - $ blindpay virtual_accounts create --receiver-id --blockchain-wallet-id `) + $ blindpay virtual_accounts list --customer-id + $ blindpay virtual_accounts create --customer-id --blockchain-wallet-id `) virtualAccounts .command('list') - .description('List virtual accounts for a receiver') - .requiredOption('--receiver-id ', 'Receiver ID') + .description('List virtual accounts for a customer') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action(opts => listVirtualAccounts(opts)) virtualAccounts .command('create') .description('Create a virtual account') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .requiredOption('--blockchain-wallet-id ', 'Blockchain wallet ID') .option('--json', 'Output as JSON', false) .action(opts => createVirtualAccount(opts)) @@ -530,12 +538,12 @@ virtualAccounts const offrampWallets = program.command('offramp_wallets').description('Manage offramp wallets') .addHelpText('after', ` Examples: - $ blindpay offramp_wallets list --receiver-id --bank-account-id `) + $ blindpay offramp_wallets list --customer-id --bank-account-id `) offrampWallets .command('list') .description('List offramp wallets') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .requiredOption('--bank-account-id ', 'Bank account ID') .option('--json', 'Output as JSON', false) .action(opts => listOfframpWallets(opts)) @@ -596,37 +604,37 @@ available const wallets = program.command('wallets').description('Manage custodial wallets (BlindPay-managed, with balance)') .addHelpText('after', ` Examples: - $ blindpay wallets list --receiver-id - $ blindpay wallets get --receiver-id - $ blindpay wallets balance --receiver-id - $ blindpay wallets create --receiver-id --network polygon --name "Main Wallet" - $ blindpay wallets delete --receiver-id `) + $ blindpay wallets list --customer-id + $ blindpay wallets get --customer-id + $ blindpay wallets balance --customer-id + $ blindpay wallets create --customer-id --network polygon --name "Main Wallet" + $ blindpay wallets delete --customer-id `) wallets .command('list') - .description('List custodial wallets for a receiver') - .requiredOption('--receiver-id ', 'Receiver ID') + .description('List custodial wallets for a customer') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action(opts => listWallets(opts)) wallets .command('get ') .description('Get a custodial wallet by ID') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => getWallet(id, opts)) wallets .command('balance ') .description('Get a custodial wallet balance (USDC/USDT/USDB)') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => getWalletBalance(id, opts)) wallets .command('create') .description('Create a new custodial wallet') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .requiredOption('--network ', 'Network') .requiredOption('--name ', 'Wallet name') .option('--external-id ', 'External ID') @@ -636,7 +644,7 @@ wallets wallets .command('delete ') .description('Delete a custodial wallet') - .requiredOption('--receiver-id ', 'Receiver ID') + .requiredOption('--customer-id ', 'Customer ID') .option('--json', 'Output as JSON', false) .action((id, opts) => deleteWallet(id, opts)) @@ -715,13 +723,13 @@ const tos = program.command('tos').description('Initiate Terms of Service flow') .addHelpText('after', ` Examples: $ blindpay tos initiate --idempotency-key - $ blindpay tos initiate --idempotency-key --receiver-id --redirect-url https://example.com`) + $ blindpay tos initiate --idempotency-key --customer-id --redirect-url https://example.com`) tos .command('initiate') .description('Initiate a Terms of Service session and return a hosted URL') .requiredOption('--idempotency-key ', 'Idempotency key') - .option('--receiver-id ', 'Receiver ID') + .option('--customer-id ', 'Customer ID') .option('--redirect-url ', 'Redirect URL after acceptance') .option('--json', 'Output as JSON', false) .action(opts => initiateTos(opts)) @@ -747,12 +755,12 @@ const schema = program.command('schema').description('Introspect CLI resource sc .addHelpText('after', ` Examples: $ blindpay schema # list all resources - $ blindpay schema receivers # full schema for receivers + $ blindpay schema customers # full schema for customers $ blindpay schema bank_accounts # schema + available rails $ blindpay schema bank_accounts --rail ach # schema + rail-specific fields`) schema - .argument('[resource]', 'Resource name (e.g. receivers, payouts, bank_accounts)') + .argument('[resource]', 'Resource name (e.g. customers, payouts, bank_accounts)') .option('--rail ', 'Show rail-specific fields (bank_accounts only)') .action((resource, opts) => { if (!resource) {