Initial Node.js SDK v1.0.0
This commit is contained in:
143
README.md
Normal file
143
README.md
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# FetcherPay Node.js SDK
|
||||||
|
|
||||||
|
Official Node.js SDK for the FetcherPay API — One API. Every Rail.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @fetcherpay/node
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { FetcherPay } from '@fetcherpay/node';
|
||||||
|
|
||||||
|
const client = new FetcherPay({
|
||||||
|
apiKey: 'fp_test_your_key',
|
||||||
|
environment: 'sandbox', // or 'production'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a payment
|
||||||
|
const payment = await client.payments.create({
|
||||||
|
amount: 10000, // $100.00 in cents
|
||||||
|
currency: 'USD',
|
||||||
|
source: { payment_method_id: 'pm_123' },
|
||||||
|
destination: { payment_method_id: 'pm_456' },
|
||||||
|
rail: 'auto', // Auto-select optimal rail
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(payment.id, payment.status);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Option | Type | Default | Description |
|
||||||
|
|--------|------|---------|-------------|
|
||||||
|
| `apiKey` | string | required | Your FetcherPay API key |
|
||||||
|
| `environment` | 'sandbox' \| 'production' | 'sandbox' | API environment |
|
||||||
|
| `baseUrl` | string | auto | Override base URL |
|
||||||
|
| `timeout` | number | 30000 | Request timeout (ms) |
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### Payments
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Create payment
|
||||||
|
const payment = await client.payments.create({
|
||||||
|
amount: 10000,
|
||||||
|
source: { payment_method_id: 'pm_123' },
|
||||||
|
destination: { payment_method_id: 'pm_456' },
|
||||||
|
}, 'unique-idempotency-key');
|
||||||
|
|
||||||
|
// Retrieve payment
|
||||||
|
const payment = await client.payments.retrieve('pay_xxx');
|
||||||
|
|
||||||
|
// List payments
|
||||||
|
const payments = await client.payments.list({ limit: 10 });
|
||||||
|
|
||||||
|
// Cancel payment
|
||||||
|
await client.payments.cancel('pay_xxx', 'Customer request');
|
||||||
|
|
||||||
|
// Refund payment
|
||||||
|
await client.payments.refund('pay_xxx', { amount: 5000, reason: 'Partial refund' });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ledger
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// List accounts
|
||||||
|
const accounts = await client.ledger.listAccounts();
|
||||||
|
|
||||||
|
// Get account balance
|
||||||
|
const account = await client.ledger.retrieveAccount('la_xxx');
|
||||||
|
console.log(account.balance.available);
|
||||||
|
|
||||||
|
// List entries
|
||||||
|
const entries = await client.ledger.listEntries({ account_id: 'la_xxx' });
|
||||||
|
```
|
||||||
|
|
||||||
|
### Payment Methods
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Create bank account
|
||||||
|
const pm = await client.paymentMethods.create({
|
||||||
|
type: 'bank_account',
|
||||||
|
bank_account: {
|
||||||
|
account_number: '000123456789',
|
||||||
|
routing_number: '011000015',
|
||||||
|
account_type: 'checking',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// List payment methods
|
||||||
|
const methods = await client.paymentMethods.list();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Webhooks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Create webhook endpoint
|
||||||
|
const webhook = await client.webhooks.create({
|
||||||
|
url: 'https://your-app.com/webhooks',
|
||||||
|
events: ['payment.settled', 'payment.failed'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify webhook signature
|
||||||
|
const isValid = client.verifyWebhookSignature(
|
||||||
|
payload,
|
||||||
|
signature, // from X-FetcherPay-Signature header
|
||||||
|
webhook.secret
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { FetcherPayError, AuthenticationError, ValidationError } from '@fetcherpay/node';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.payments.create({...});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AuthenticationError) {
|
||||||
|
console.error('Invalid API key');
|
||||||
|
} else if (error instanceof ValidationError) {
|
||||||
|
console.error('Validation failed:', error.param);
|
||||||
|
} else if (error instanceof FetcherPayError) {
|
||||||
|
console.error('API error:', error.type, error.statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
Full TypeScript support with exported types:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Payment, CreatePaymentRequest, PaymentStatus } from '@fetcherpay/node';
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
31
dist/api/ledger.d.ts
vendored
Normal file
31
dist/api/ledger.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import { LedgerAccount, LedgerEntry, ListResponse, PaginationParams } from '../types';
|
||||||
|
/**
|
||||||
|
* Ledger API client
|
||||||
|
*/
|
||||||
|
export declare class LedgerClient {
|
||||||
|
private http;
|
||||||
|
constructor(http: AxiosInstance);
|
||||||
|
/**
|
||||||
|
* List all ledger accounts
|
||||||
|
*/
|
||||||
|
listAccounts(params?: PaginationParams & {
|
||||||
|
type?: string;
|
||||||
|
}): Promise<ListResponse<LedgerAccount>>;
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger account by ID
|
||||||
|
*/
|
||||||
|
retrieveAccount(accountId: string): Promise<LedgerAccount>;
|
||||||
|
/**
|
||||||
|
* List all ledger entries
|
||||||
|
*/
|
||||||
|
listEntries(params?: PaginationParams & {
|
||||||
|
account_id?: string;
|
||||||
|
payment_id?: string;
|
||||||
|
entry_type?: string;
|
||||||
|
}): Promise<ListResponse<LedgerEntry>>;
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger entry by ID
|
||||||
|
*/
|
||||||
|
retrieveEntry(entryId: string): Promise<LedgerEntry>;
|
||||||
|
}
|
||||||
27
dist/api/payment-methods.d.ts
vendored
Normal file
27
dist/api/payment-methods.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import { PaymentMethod, CreatePaymentMethodRequest, ListResponse, PaginationParams } from '../types';
|
||||||
|
/**
|
||||||
|
* Payment Methods API client
|
||||||
|
*/
|
||||||
|
export declare class PaymentMethodsClient {
|
||||||
|
private http;
|
||||||
|
constructor(http: AxiosInstance);
|
||||||
|
/**
|
||||||
|
* Create a new payment method
|
||||||
|
*/
|
||||||
|
create(params: CreatePaymentMethodRequest, idempotencyKey?: string): Promise<PaymentMethod>;
|
||||||
|
/**
|
||||||
|
* Retrieve a payment method by ID
|
||||||
|
*/
|
||||||
|
retrieve(paymentMethodId: string): Promise<PaymentMethod>;
|
||||||
|
/**
|
||||||
|
* List all payment methods
|
||||||
|
*/
|
||||||
|
list(params?: PaginationParams & {
|
||||||
|
type?: string;
|
||||||
|
}): Promise<ListResponse<PaymentMethod>>;
|
||||||
|
/**
|
||||||
|
* Delete a payment method
|
||||||
|
*/
|
||||||
|
delete(paymentMethodId: string): Promise<void>;
|
||||||
|
}
|
||||||
35
dist/api/payments.d.ts
vendored
Normal file
35
dist/api/payments.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import { Payment, CreatePaymentRequest, ListResponse, PaginationParams, FilterParams } from '../types';
|
||||||
|
/**
|
||||||
|
* Payments API client
|
||||||
|
*/
|
||||||
|
export declare class PaymentsClient {
|
||||||
|
private http;
|
||||||
|
constructor(http: AxiosInstance);
|
||||||
|
/**
|
||||||
|
* Create a new payment
|
||||||
|
*/
|
||||||
|
create(params: CreatePaymentRequest, idempotencyKey?: string): Promise<Payment>;
|
||||||
|
/**
|
||||||
|
* Retrieve a payment by ID
|
||||||
|
*/
|
||||||
|
retrieve(paymentId: string): Promise<Payment>;
|
||||||
|
/**
|
||||||
|
* List all payments
|
||||||
|
*/
|
||||||
|
list(params?: PaginationParams & FilterParams & {
|
||||||
|
status?: string;
|
||||||
|
rail?: string;
|
||||||
|
}): Promise<ListResponse<Payment>>;
|
||||||
|
/**
|
||||||
|
* Cancel a pending payment
|
||||||
|
*/
|
||||||
|
cancel(paymentId: string, reason?: string, idempotencyKey?: string): Promise<Payment>;
|
||||||
|
/**
|
||||||
|
* Refund a settled payment
|
||||||
|
*/
|
||||||
|
refund(paymentId: string, params?: {
|
||||||
|
amount?: number;
|
||||||
|
reason?: string;
|
||||||
|
}, idempotencyKey?: string): Promise<Payment>;
|
||||||
|
}
|
||||||
29
dist/api/webhooks.d.ts
vendored
Normal file
29
dist/api/webhooks.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import { WebhookEndpoint, CreateWebhookRequest, ListResponse, PaginationParams } from '../types';
|
||||||
|
/**
|
||||||
|
* Webhooks API client
|
||||||
|
*/
|
||||||
|
export declare class WebhooksClient {
|
||||||
|
private http;
|
||||||
|
constructor(http: AxiosInstance);
|
||||||
|
/**
|
||||||
|
* Create a new webhook endpoint
|
||||||
|
*/
|
||||||
|
create(params: CreateWebhookRequest, idempotencyKey?: string): Promise<WebhookEndpoint>;
|
||||||
|
/**
|
||||||
|
* Retrieve a webhook endpoint by ID
|
||||||
|
*/
|
||||||
|
retrieve(webhookId: string): Promise<WebhookEndpoint>;
|
||||||
|
/**
|
||||||
|
* List all webhook endpoints
|
||||||
|
*/
|
||||||
|
list(params?: PaginationParams): Promise<ListResponse<WebhookEndpoint>>;
|
||||||
|
/**
|
||||||
|
* Update a webhook endpoint
|
||||||
|
*/
|
||||||
|
update(webhookId: string, params: Partial<CreateWebhookRequest>): Promise<WebhookEndpoint>;
|
||||||
|
/**
|
||||||
|
* Delete a webhook endpoint
|
||||||
|
*/
|
||||||
|
delete(webhookId: string): Promise<void>;
|
||||||
|
}
|
||||||
21
dist/client.d.ts
vendored
Normal file
21
dist/client.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { FetcherPayConfig } from './types';
|
||||||
|
import { PaymentsClient } from './api/payments';
|
||||||
|
import { LedgerClient } from './api/ledger';
|
||||||
|
import { PaymentMethodsClient } from './api/payment-methods';
|
||||||
|
import { WebhooksClient } from './api/webhooks';
|
||||||
|
/**
|
||||||
|
* Main FetcherPay client
|
||||||
|
*/
|
||||||
|
export declare class FetcherPay {
|
||||||
|
private http;
|
||||||
|
payments: PaymentsClient;
|
||||||
|
ledger: LedgerClient;
|
||||||
|
paymentMethods: PaymentMethodsClient;
|
||||||
|
webhooks: WebhooksClient;
|
||||||
|
constructor(config: FetcherPayConfig);
|
||||||
|
/**
|
||||||
|
* Verify webhook signature
|
||||||
|
*/
|
||||||
|
verifyWebhookSignature(payload: string, signature: string, secret: string): boolean;
|
||||||
|
}
|
||||||
|
export default FetcherPay;
|
||||||
27
dist/index.d.ts
vendored
Normal file
27
dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay Node.js SDK
|
||||||
|
* One API. Every Rail.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* import { FetcherPay } from '@fetcherpay/node';
|
||||||
|
*
|
||||||
|
* const client = new FetcherPay({
|
||||||
|
* apiKey: 'fp_test_your_key',
|
||||||
|
* environment: 'sandbox'
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* const payment = await client.payments.create({
|
||||||
|
* amount: 10000,
|
||||||
|
* currency: 'USD',
|
||||||
|
* source: { payment_method_id: 'pm_123' },
|
||||||
|
* destination: { payment_method_id: 'pm_456' }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export { FetcherPay } from './client';
|
||||||
|
export { PaymentsClient } from './api/payments';
|
||||||
|
export { LedgerClient } from './api/ledger';
|
||||||
|
export { PaymentMethodsClient } from './api/payment-methods';
|
||||||
|
export { WebhooksClient } from './api/webhooks';
|
||||||
|
export * from './types';
|
||||||
271
dist/index.esm.js
vendored
Normal file
271
dist/index.esm.js
vendored
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FetcherPay SDK Types
|
||||||
|
*/
|
||||||
|
class FetcherPayError extends Error {
|
||||||
|
constructor(message, type, statusCode, param, code) {
|
||||||
|
super(message);
|
||||||
|
this.type = type;
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
this.param = param;
|
||||||
|
this.code = code;
|
||||||
|
this.name = 'FetcherPayError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class AuthenticationError extends FetcherPayError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message, 'authentication_error', 401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class ValidationError extends FetcherPayError {
|
||||||
|
constructor(message, param) {
|
||||||
|
super(message, 'validation_error', 422, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class NotFoundError extends FetcherPayError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message, 'not_found', 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payments API client
|
||||||
|
*/
|
||||||
|
class PaymentsClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new payment
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/payments', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a payment by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentId) {
|
||||||
|
const response = await this.http.get(`/payments/${paymentId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all payments
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/payments', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Cancel a pending payment
|
||||||
|
*/
|
||||||
|
async cancel(paymentId, reason, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post(`/payments/${paymentId}/cancel`, reason ? { reason } : {}, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Refund a settled payment
|
||||||
|
*/
|
||||||
|
async refund(paymentId, params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post(`/payments/${paymentId}/refund`, params || {}, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ledger API client
|
||||||
|
*/
|
||||||
|
class LedgerClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all ledger accounts
|
||||||
|
*/
|
||||||
|
async listAccounts(params) {
|
||||||
|
const response = await this.http.get('/ledger/accounts', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger account by ID
|
||||||
|
*/
|
||||||
|
async retrieveAccount(accountId) {
|
||||||
|
const response = await this.http.get(`/ledger/accounts/${accountId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all ledger entries
|
||||||
|
*/
|
||||||
|
async listEntries(params) {
|
||||||
|
const response = await this.http.get('/ledger/entries', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger entry by ID
|
||||||
|
*/
|
||||||
|
async retrieveEntry(entryId) {
|
||||||
|
const response = await this.http.get(`/ledger/entries/${entryId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment Methods API client
|
||||||
|
*/
|
||||||
|
class PaymentMethodsClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new payment method
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/payment-methods', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a payment method by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentMethodId) {
|
||||||
|
const response = await this.http.get(`/payment-methods/${paymentMethodId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all payment methods
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/payment-methods', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Delete a payment method
|
||||||
|
*/
|
||||||
|
async delete(paymentMethodId) {
|
||||||
|
await this.http.delete(`/payment-methods/${paymentMethodId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhooks API client
|
||||||
|
*/
|
||||||
|
class WebhooksClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new webhook endpoint
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/webhooks', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a webhook endpoint by ID
|
||||||
|
*/
|
||||||
|
async retrieve(webhookId) {
|
||||||
|
const response = await this.http.get(`/webhooks/${webhookId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all webhook endpoints
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/webhooks', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Update a webhook endpoint
|
||||||
|
*/
|
||||||
|
async update(webhookId, params) {
|
||||||
|
const response = await this.http.put(`/webhooks/${webhookId}`, params);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Delete a webhook endpoint
|
||||||
|
*/
|
||||||
|
async delete(webhookId) {
|
||||||
|
await this.http.delete(`/webhooks/${webhookId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main FetcherPay client
|
||||||
|
*/
|
||||||
|
class FetcherPay {
|
||||||
|
constructor(config) {
|
||||||
|
const baseUrl = config.baseUrl || (config.environment === 'production'
|
||||||
|
? 'https://api.fetcherpay.com/v1'
|
||||||
|
: 'https://sandbox.fetcherpay.com/v1');
|
||||||
|
this.http = axios.create({
|
||||||
|
baseURL: baseUrl,
|
||||||
|
timeout: config.timeout || 30000,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${config.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Response interceptor for error handling
|
||||||
|
this.http.interceptors.response.use((response) => response, (error) => {
|
||||||
|
if (error.response) {
|
||||||
|
const { status, data } = error.response;
|
||||||
|
const errorData = data?.error || {};
|
||||||
|
switch (status) {
|
||||||
|
case 401:
|
||||||
|
throw new AuthenticationError(errorData.message || 'Authentication failed');
|
||||||
|
case 404:
|
||||||
|
throw new NotFoundError(errorData.message || 'Resource not found');
|
||||||
|
case 422:
|
||||||
|
throw new ValidationError(errorData.message || 'Validation failed', errorData.param);
|
||||||
|
default:
|
||||||
|
throw new FetcherPayError(errorData.message || 'An error occurred', errorData.type || 'api_error', status, errorData.param, errorData.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
// Initialize API clients
|
||||||
|
this.payments = new PaymentsClient(this.http);
|
||||||
|
this.ledger = new LedgerClient(this.http);
|
||||||
|
this.paymentMethods = new PaymentMethodsClient(this.http);
|
||||||
|
this.webhooks = new WebhooksClient(this.http);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Verify webhook signature
|
||||||
|
*/
|
||||||
|
verifyWebhookSignature(payload, signature, secret) {
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const expected = crypto
|
||||||
|
.createHmac('sha256', secret)
|
||||||
|
.update(payload)
|
||||||
|
.digest('hex');
|
||||||
|
try {
|
||||||
|
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AuthenticationError, FetcherPay, FetcherPayError, LedgerClient, NotFoundError, PaymentMethodsClient, PaymentsClient, ValidationError, WebhooksClient };
|
||||||
|
//# sourceMappingURL=index.esm.js.map
|
||||||
1
dist/index.esm.js.map
vendored
Normal file
1
dist/index.esm.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
281
dist/index.js
vendored
Normal file
281
dist/index.js
vendored
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var axios = require('axios');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FetcherPay SDK Types
|
||||||
|
*/
|
||||||
|
class FetcherPayError extends Error {
|
||||||
|
constructor(message, type, statusCode, param, code) {
|
||||||
|
super(message);
|
||||||
|
this.type = type;
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
this.param = param;
|
||||||
|
this.code = code;
|
||||||
|
this.name = 'FetcherPayError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class AuthenticationError extends FetcherPayError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message, 'authentication_error', 401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class ValidationError extends FetcherPayError {
|
||||||
|
constructor(message, param) {
|
||||||
|
super(message, 'validation_error', 422, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class NotFoundError extends FetcherPayError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message, 'not_found', 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payments API client
|
||||||
|
*/
|
||||||
|
class PaymentsClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new payment
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/payments', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a payment by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentId) {
|
||||||
|
const response = await this.http.get(`/payments/${paymentId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all payments
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/payments', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Cancel a pending payment
|
||||||
|
*/
|
||||||
|
async cancel(paymentId, reason, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post(`/payments/${paymentId}/cancel`, reason ? { reason } : {}, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Refund a settled payment
|
||||||
|
*/
|
||||||
|
async refund(paymentId, params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post(`/payments/${paymentId}/refund`, params || {}, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ledger API client
|
||||||
|
*/
|
||||||
|
class LedgerClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all ledger accounts
|
||||||
|
*/
|
||||||
|
async listAccounts(params) {
|
||||||
|
const response = await this.http.get('/ledger/accounts', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger account by ID
|
||||||
|
*/
|
||||||
|
async retrieveAccount(accountId) {
|
||||||
|
const response = await this.http.get(`/ledger/accounts/${accountId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all ledger entries
|
||||||
|
*/
|
||||||
|
async listEntries(params) {
|
||||||
|
const response = await this.http.get('/ledger/entries', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger entry by ID
|
||||||
|
*/
|
||||||
|
async retrieveEntry(entryId) {
|
||||||
|
const response = await this.http.get(`/ledger/entries/${entryId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment Methods API client
|
||||||
|
*/
|
||||||
|
class PaymentMethodsClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new payment method
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/payment-methods', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a payment method by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentMethodId) {
|
||||||
|
const response = await this.http.get(`/payment-methods/${paymentMethodId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all payment methods
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/payment-methods', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Delete a payment method
|
||||||
|
*/
|
||||||
|
async delete(paymentMethodId) {
|
||||||
|
await this.http.delete(`/payment-methods/${paymentMethodId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhooks API client
|
||||||
|
*/
|
||||||
|
class WebhooksClient {
|
||||||
|
constructor(http) {
|
||||||
|
this.http = http;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create a new webhook endpoint
|
||||||
|
*/
|
||||||
|
async create(params, idempotencyKey) {
|
||||||
|
const headers = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
const response = await this.http.post('/webhooks', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a webhook endpoint by ID
|
||||||
|
*/
|
||||||
|
async retrieve(webhookId) {
|
||||||
|
const response = await this.http.get(`/webhooks/${webhookId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List all webhook endpoints
|
||||||
|
*/
|
||||||
|
async list(params) {
|
||||||
|
const response = await this.http.get('/webhooks', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Update a webhook endpoint
|
||||||
|
*/
|
||||||
|
async update(webhookId, params) {
|
||||||
|
const response = await this.http.put(`/webhooks/${webhookId}`, params);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Delete a webhook endpoint
|
||||||
|
*/
|
||||||
|
async delete(webhookId) {
|
||||||
|
await this.http.delete(`/webhooks/${webhookId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main FetcherPay client
|
||||||
|
*/
|
||||||
|
class FetcherPay {
|
||||||
|
constructor(config) {
|
||||||
|
const baseUrl = config.baseUrl || (config.environment === 'production'
|
||||||
|
? 'https://api.fetcherpay.com/v1'
|
||||||
|
: 'https://sandbox.fetcherpay.com/v1');
|
||||||
|
this.http = axios.create({
|
||||||
|
baseURL: baseUrl,
|
||||||
|
timeout: config.timeout || 30000,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${config.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Response interceptor for error handling
|
||||||
|
this.http.interceptors.response.use((response) => response, (error) => {
|
||||||
|
if (error.response) {
|
||||||
|
const { status, data } = error.response;
|
||||||
|
const errorData = data?.error || {};
|
||||||
|
switch (status) {
|
||||||
|
case 401:
|
||||||
|
throw new AuthenticationError(errorData.message || 'Authentication failed');
|
||||||
|
case 404:
|
||||||
|
throw new NotFoundError(errorData.message || 'Resource not found');
|
||||||
|
case 422:
|
||||||
|
throw new ValidationError(errorData.message || 'Validation failed', errorData.param);
|
||||||
|
default:
|
||||||
|
throw new FetcherPayError(errorData.message || 'An error occurred', errorData.type || 'api_error', status, errorData.param, errorData.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
// Initialize API clients
|
||||||
|
this.payments = new PaymentsClient(this.http);
|
||||||
|
this.ledger = new LedgerClient(this.http);
|
||||||
|
this.paymentMethods = new PaymentMethodsClient(this.http);
|
||||||
|
this.webhooks = new WebhooksClient(this.http);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Verify webhook signature
|
||||||
|
*/
|
||||||
|
verifyWebhookSignature(payload, signature, secret) {
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const expected = crypto
|
||||||
|
.createHmac('sha256', secret)
|
||||||
|
.update(payload)
|
||||||
|
.digest('hex');
|
||||||
|
try {
|
||||||
|
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.AuthenticationError = AuthenticationError;
|
||||||
|
exports.FetcherPay = FetcherPay;
|
||||||
|
exports.FetcherPayError = FetcherPayError;
|
||||||
|
exports.LedgerClient = LedgerClient;
|
||||||
|
exports.NotFoundError = NotFoundError;
|
||||||
|
exports.PaymentMethodsClient = PaymentMethodsClient;
|
||||||
|
exports.PaymentsClient = PaymentsClient;
|
||||||
|
exports.ValidationError = ValidationError;
|
||||||
|
exports.WebhooksClient = WebhooksClient;
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
dist/index.js.map
vendored
Normal file
1
dist/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
192
dist/types/index.d.ts
vendored
Normal file
192
dist/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay SDK Types
|
||||||
|
*/
|
||||||
|
export interface FetcherPayConfig {
|
||||||
|
apiKey: string;
|
||||||
|
environment?: 'sandbox' | 'production';
|
||||||
|
baseUrl?: string;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
export interface Payment {
|
||||||
|
id: string;
|
||||||
|
object: 'payment';
|
||||||
|
status: 'pending' | 'authorized' | 'processing' | 'settled' | 'failed' | 'cancelled' | 'refunded' | 'partially_refunded';
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
rail: string;
|
||||||
|
rail_selected: string;
|
||||||
|
description?: string;
|
||||||
|
source: PaymentSource;
|
||||||
|
destination: PaymentDestination;
|
||||||
|
fee?: Fee;
|
||||||
|
timeline: TimelineEvent[];
|
||||||
|
ledger_entry_ids: string[];
|
||||||
|
refunds: Refund[];
|
||||||
|
idempotency_key?: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
export interface PaymentSource {
|
||||||
|
payment_method_id: string;
|
||||||
|
name?: string | null;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
export interface PaymentDestination {
|
||||||
|
payment_method_id: string;
|
||||||
|
name?: string | null;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
export interface Fee {
|
||||||
|
amount: number;
|
||||||
|
rate: string;
|
||||||
|
}
|
||||||
|
export interface TimelineEvent {
|
||||||
|
status: string;
|
||||||
|
timestamp: string;
|
||||||
|
detail: string;
|
||||||
|
}
|
||||||
|
export interface Refund {
|
||||||
|
id: string;
|
||||||
|
payment_id: string;
|
||||||
|
amount: number;
|
||||||
|
reason?: string | null;
|
||||||
|
status: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
export interface CreatePaymentRequest {
|
||||||
|
amount: number;
|
||||||
|
currency?: string;
|
||||||
|
rail?: 'auto' | 'ach' | 'rtp' | 'card' | 'crypto';
|
||||||
|
rail_fallback_order?: string[];
|
||||||
|
description?: string;
|
||||||
|
source: PaymentSource;
|
||||||
|
destination: PaymentDestination;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
export interface PaymentMethod {
|
||||||
|
id: string;
|
||||||
|
object: 'payment_method';
|
||||||
|
type: 'bank_account' | 'card' | 'usdc_wallet';
|
||||||
|
status: 'active' | 'inactive' | 'verification_required';
|
||||||
|
bank_account?: BankAccount;
|
||||||
|
card?: Card;
|
||||||
|
usdc_wallet?: UsdcWallet;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
export interface BankAccount {
|
||||||
|
account_type: 'checking' | 'savings';
|
||||||
|
bank_name?: string;
|
||||||
|
routing_number_last4: string;
|
||||||
|
account_number_last4: string;
|
||||||
|
}
|
||||||
|
export interface Card {
|
||||||
|
brand: string;
|
||||||
|
last4: string;
|
||||||
|
exp_month: number;
|
||||||
|
exp_year: number;
|
||||||
|
}
|
||||||
|
export interface UsdcWallet {
|
||||||
|
address: string;
|
||||||
|
network: 'ethereum' | 'polygon';
|
||||||
|
}
|
||||||
|
export interface CreatePaymentMethodRequest {
|
||||||
|
type: 'bank_account' | 'card' | 'usdc_wallet';
|
||||||
|
bank_account?: {
|
||||||
|
account_number: string;
|
||||||
|
routing_number: string;
|
||||||
|
account_type: 'checking' | 'savings';
|
||||||
|
};
|
||||||
|
card?: {
|
||||||
|
number: string;
|
||||||
|
exp_month: number;
|
||||||
|
exp_year: number;
|
||||||
|
cvc: string;
|
||||||
|
};
|
||||||
|
usdc_wallet?: {
|
||||||
|
address: string;
|
||||||
|
network: string;
|
||||||
|
};
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
export interface LedgerAccount {
|
||||||
|
id: string;
|
||||||
|
object: 'ledger_account';
|
||||||
|
name: string;
|
||||||
|
type: 'asset' | 'liability' | 'revenue' | 'expense' | 'equity';
|
||||||
|
currency: string;
|
||||||
|
balance: {
|
||||||
|
pending: number;
|
||||||
|
posted: number;
|
||||||
|
available: number;
|
||||||
|
};
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
export interface LedgerEntry {
|
||||||
|
id: string;
|
||||||
|
object: 'ledger_entry';
|
||||||
|
journal_id: string;
|
||||||
|
account_id: string;
|
||||||
|
payment_id?: string;
|
||||||
|
entry_type: 'debit' | 'credit';
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
status: 'pending' | 'posted';
|
||||||
|
description?: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
export interface WebhookEndpoint {
|
||||||
|
id: string;
|
||||||
|
object: 'webhook_endpoint';
|
||||||
|
url: string;
|
||||||
|
events: string[];
|
||||||
|
status: 'active' | 'disabled';
|
||||||
|
secret: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
export interface CreateWebhookRequest {
|
||||||
|
url: string;
|
||||||
|
events?: string[];
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
export interface WebhookEvent {
|
||||||
|
id: string;
|
||||||
|
object: 'event';
|
||||||
|
type: string;
|
||||||
|
created_at: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
export interface ListResponse<T> {
|
||||||
|
data: T[];
|
||||||
|
has_more: boolean;
|
||||||
|
next_cursor: string | null;
|
||||||
|
}
|
||||||
|
export interface PaginationParams {
|
||||||
|
cursor?: string;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
export interface FilterParams {
|
||||||
|
created_after?: string;
|
||||||
|
created_before?: string;
|
||||||
|
}
|
||||||
|
export declare class FetcherPayError extends Error {
|
||||||
|
type: string;
|
||||||
|
statusCode?: number | undefined;
|
||||||
|
param?: string | null | undefined;
|
||||||
|
code?: string | null | undefined;
|
||||||
|
constructor(message: string, type: string, statusCode?: number | undefined, param?: string | null | undefined, code?: string | null | undefined);
|
||||||
|
}
|
||||||
|
export declare class AuthenticationError extends FetcherPayError {
|
||||||
|
constructor(message: string);
|
||||||
|
}
|
||||||
|
export declare class ValidationError extends FetcherPayError {
|
||||||
|
constructor(message: string, param?: string);
|
||||||
|
}
|
||||||
|
export declare class NotFoundError extends FetcherPayError {
|
||||||
|
constructor(message: string);
|
||||||
|
}
|
||||||
54
examples/basic.ts
Normal file
54
examples/basic.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay Node.js SDK - Basic Example
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FetcherPay } from '../src';
|
||||||
|
|
||||||
|
// Initialize client
|
||||||
|
const client = new FetcherPay({
|
||||||
|
apiKey: process.env.FETCHERPAY_API_KEY || 'sandbox',
|
||||||
|
environment: 'sandbox',
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
// Create a payment
|
||||||
|
console.log('Creating payment...');
|
||||||
|
const payment = await client.payments.create({
|
||||||
|
amount: 10000, // $100.00 in cents
|
||||||
|
currency: 'USD',
|
||||||
|
source: {
|
||||||
|
payment_method_id: 'pm_bank_123',
|
||||||
|
},
|
||||||
|
destination: {
|
||||||
|
payment_method_id: 'pm_merchant_456',
|
||||||
|
},
|
||||||
|
rail: 'auto', // Let FetcherPay choose optimal rail
|
||||||
|
});
|
||||||
|
console.log('Payment created:', payment.id, 'Status:', payment.status);
|
||||||
|
|
||||||
|
// Retrieve the payment
|
||||||
|
console.log('\nRetrieving payment...');
|
||||||
|
const retrieved = await client.payments.retrieve(payment.id);
|
||||||
|
console.log('Retrieved:', retrieved.id, 'Timeline:', retrieved.timeline.length, 'events');
|
||||||
|
|
||||||
|
// List payments
|
||||||
|
console.log('\nListing payments...');
|
||||||
|
const payments = await client.payments.list({ limit: 5 });
|
||||||
|
console.log(`Found ${payments.data.length} payments`);
|
||||||
|
|
||||||
|
// List ledger accounts
|
||||||
|
console.log('\nListing ledger accounts...');
|
||||||
|
const accounts = await client.ledger.listAccounts();
|
||||||
|
console.log(`Found ${accounts.data.length} accounts`);
|
||||||
|
accounts.data.forEach(acc => {
|
||||||
|
console.log(` - ${acc.name}: $${acc.balance.available / 100} available`);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
40
examples/webhook-verification.ts
Normal file
40
examples/webhook-verification.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay Node.js SDK - Webhook Verification Example
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FetcherPay } from '../src';
|
||||||
|
|
||||||
|
const client = new FetcherPay({
|
||||||
|
apiKey: 'sandbox',
|
||||||
|
environment: 'sandbox',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example webhook payload
|
||||||
|
const payload = JSON.stringify({
|
||||||
|
id: 'evt_123',
|
||||||
|
type: 'payment.settled',
|
||||||
|
created_at: '2026-02-18T20:00:00Z',
|
||||||
|
data: {
|
||||||
|
id: 'pay_456',
|
||||||
|
status: 'settled',
|
||||||
|
amount: 10000,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Your webhook secret from the dashboard
|
||||||
|
const webhookSecret = 'whsec_your_secret_here';
|
||||||
|
|
||||||
|
// Simulate receiving a webhook
|
||||||
|
const signature = 'sha256=...'; // From X-FetcherPay-Signature header
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
const isValid = client.verifyWebhookSignature(payload, signature, webhookSecret);
|
||||||
|
|
||||||
|
if (isValid) {
|
||||||
|
console.log('✅ Webhook signature verified');
|
||||||
|
// Process the webhook event
|
||||||
|
const event = JSON.parse(payload);
|
||||||
|
console.log('Event type:', event.type);
|
||||||
|
} else {
|
||||||
|
console.log('❌ Invalid webhook signature');
|
||||||
|
}
|
||||||
35
package.json
Normal file
35
package.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "@fetcherpay/node",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "FetcherPay Node.js SDK",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.esm.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c",
|
||||||
|
"dev": "rollup -c -w",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"lint": "eslint src/**/*.ts",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"keywords": ["payments", "fintech", "api", "fetcherpay"],
|
||||||
|
"author": "FetcherPay",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.5.0",
|
||||||
|
"crypto": "^1.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-typescript": "^11.1.0",
|
||||||
|
"@types/jest": "^29.5.0",
|
||||||
|
"@types/node": "^20.0.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
|
"eslint": "^8.0.0",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"rollup": "^3.29.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
27
rollup.config.js
Normal file
27
rollup.config.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import typescript from '@rollup/plugin-typescript';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// ES Module build
|
||||||
|
{
|
||||||
|
input: 'src/index.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/index.esm.js',
|
||||||
|
format: 'es',
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
plugins: [typescript({ tsconfig: './tsconfig.json' })],
|
||||||
|
external: ['axios', 'crypto'],
|
||||||
|
},
|
||||||
|
// CommonJS build
|
||||||
|
{
|
||||||
|
input: 'src/index.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/index.js',
|
||||||
|
format: 'cjs',
|
||||||
|
sourcemap: true,
|
||||||
|
exports: 'named',
|
||||||
|
},
|
||||||
|
plugins: [typescript({ tsconfig: './tsconfig.json' })],
|
||||||
|
external: ['axios', 'crypto'],
|
||||||
|
},
|
||||||
|
];
|
||||||
50
src/api/ledger.ts
Normal file
50
src/api/ledger.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import {
|
||||||
|
LedgerAccount,
|
||||||
|
LedgerEntry,
|
||||||
|
ListResponse,
|
||||||
|
PaginationParams,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ledger API client
|
||||||
|
*/
|
||||||
|
export class LedgerClient {
|
||||||
|
constructor(private http: AxiosInstance) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all ledger accounts
|
||||||
|
*/
|
||||||
|
async listAccounts(params?: PaginationParams & { type?: string }): Promise<ListResponse<LedgerAccount>> {
|
||||||
|
const response = await this.http.get('/ledger/accounts', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger account by ID
|
||||||
|
*/
|
||||||
|
async retrieveAccount(accountId: string): Promise<LedgerAccount> {
|
||||||
|
const response = await this.http.get(`/ledger/accounts/${accountId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all ledger entries
|
||||||
|
*/
|
||||||
|
async listEntries(params?: PaginationParams & {
|
||||||
|
account_id?: string;
|
||||||
|
payment_id?: string;
|
||||||
|
entry_type?: string;
|
||||||
|
}): Promise<ListResponse<LedgerEntry>> {
|
||||||
|
const response = await this.http.get('/ledger/entries', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a ledger entry by ID
|
||||||
|
*/
|
||||||
|
async retrieveEntry(entryId: string): Promise<LedgerEntry> {
|
||||||
|
const response = await this.http.get(`/ledger/entries/${entryId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/api/payment-methods.ts
Normal file
50
src/api/payment-methods.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import {
|
||||||
|
PaymentMethod,
|
||||||
|
CreatePaymentMethodRequest,
|
||||||
|
ListResponse,
|
||||||
|
PaginationParams,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment Methods API client
|
||||||
|
*/
|
||||||
|
export class PaymentMethodsClient {
|
||||||
|
constructor(private http: AxiosInstance) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new payment method
|
||||||
|
*/
|
||||||
|
async create(params: CreatePaymentMethodRequest, idempotencyKey?: string): Promise<PaymentMethod> {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.http.post('/payment-methods', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a payment method by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentMethodId: string): Promise<PaymentMethod> {
|
||||||
|
const response = await this.http.get(`/payment-methods/${paymentMethodId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all payment methods
|
||||||
|
*/
|
||||||
|
async list(params?: PaginationParams & { type?: string }): Promise<ListResponse<PaymentMethod>> {
|
||||||
|
const response = await this.http.get('/payment-methods', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a payment method
|
||||||
|
*/
|
||||||
|
async delete(paymentMethodId: string): Promise<void> {
|
||||||
|
await this.http.delete(`/payment-methods/${paymentMethodId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/api/payments.ts
Normal file
82
src/api/payments.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import {
|
||||||
|
Payment,
|
||||||
|
CreatePaymentRequest,
|
||||||
|
ListResponse,
|
||||||
|
PaginationParams,
|
||||||
|
FilterParams,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payments API client
|
||||||
|
*/
|
||||||
|
export class PaymentsClient {
|
||||||
|
constructor(private http: AxiosInstance) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new payment
|
||||||
|
*/
|
||||||
|
async create(params: CreatePaymentRequest, idempotencyKey?: string): Promise<Payment> {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.http.post('/payments', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a payment by ID
|
||||||
|
*/
|
||||||
|
async retrieve(paymentId: string): Promise<Payment> {
|
||||||
|
const response = await this.http.get(`/payments/${paymentId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all payments
|
||||||
|
*/
|
||||||
|
async list(params?: PaginationParams & FilterParams & { status?: string; rail?: string }): Promise<ListResponse<Payment>> {
|
||||||
|
const response = await this.http.get('/payments', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel a pending payment
|
||||||
|
*/
|
||||||
|
async cancel(paymentId: string, reason?: string, idempotencyKey?: string): Promise<Payment> {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.http.post(
|
||||||
|
`/payments/${paymentId}/cancel`,
|
||||||
|
reason ? { reason } : {},
|
||||||
|
{ headers }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refund a settled payment
|
||||||
|
*/
|
||||||
|
async refund(
|
||||||
|
paymentId: string,
|
||||||
|
params?: { amount?: number; reason?: string },
|
||||||
|
idempotencyKey?: string
|
||||||
|
): Promise<Payment> {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.http.post(
|
||||||
|
`/payments/${paymentId}/refund`,
|
||||||
|
params || {},
|
||||||
|
{ headers }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/api/webhooks.ts
Normal file
58
src/api/webhooks.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import {
|
||||||
|
WebhookEndpoint,
|
||||||
|
CreateWebhookRequest,
|
||||||
|
ListResponse,
|
||||||
|
PaginationParams,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhooks API client
|
||||||
|
*/
|
||||||
|
export class WebhooksClient {
|
||||||
|
constructor(private http: AxiosInstance) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new webhook endpoint
|
||||||
|
*/
|
||||||
|
async create(params: CreateWebhookRequest, idempotencyKey?: string): Promise<WebhookEndpoint> {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (idempotencyKey) {
|
||||||
|
headers['Idempotency-Key'] = idempotencyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.http.post('/webhooks', params, { headers });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a webhook endpoint by ID
|
||||||
|
*/
|
||||||
|
async retrieve(webhookId: string): Promise<WebhookEndpoint> {
|
||||||
|
const response = await this.http.get(`/webhooks/${webhookId}`);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all webhook endpoints
|
||||||
|
*/
|
||||||
|
async list(params?: PaginationParams): Promise<ListResponse<WebhookEndpoint>> {
|
||||||
|
const response = await this.http.get('/webhooks', { params });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a webhook endpoint
|
||||||
|
*/
|
||||||
|
async update(webhookId: string, params: Partial<CreateWebhookRequest>): Promise<WebhookEndpoint> {
|
||||||
|
const response = await this.http.put(`/webhooks/${webhookId}`, params);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a webhook endpoint
|
||||||
|
*/
|
||||||
|
async delete(webhookId: string): Promise<void> {
|
||||||
|
await this.http.delete(`/webhooks/${webhookId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
97
src/client.ts
Normal file
97
src/client.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import axios, { AxiosInstance, AxiosError } from 'axios';
|
||||||
|
import {
|
||||||
|
FetcherPayConfig,
|
||||||
|
FetcherPayError,
|
||||||
|
AuthenticationError,
|
||||||
|
ValidationError,
|
||||||
|
NotFoundError,
|
||||||
|
} from './types';
|
||||||
|
import { PaymentsClient } from './api/payments';
|
||||||
|
import { LedgerClient } from './api/ledger';
|
||||||
|
import { PaymentMethodsClient } from './api/payment-methods';
|
||||||
|
import { WebhooksClient } from './api/webhooks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main FetcherPay client
|
||||||
|
*/
|
||||||
|
export class FetcherPay {
|
||||||
|
private http: AxiosInstance;
|
||||||
|
public payments: PaymentsClient;
|
||||||
|
public ledger: LedgerClient;
|
||||||
|
public paymentMethods: PaymentMethodsClient;
|
||||||
|
public webhooks: WebhooksClient;
|
||||||
|
|
||||||
|
constructor(config: FetcherPayConfig) {
|
||||||
|
const baseUrl = config.baseUrl || (
|
||||||
|
config.environment === 'production'
|
||||||
|
? 'https://api.fetcherpay.com/v1'
|
||||||
|
: 'https://sandbox.fetcherpay.com/v1'
|
||||||
|
);
|
||||||
|
|
||||||
|
this.http = axios.create({
|
||||||
|
baseURL: baseUrl,
|
||||||
|
timeout: config.timeout || 30000,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${config.apiKey}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Response interceptor for error handling
|
||||||
|
this.http.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error: AxiosError) => {
|
||||||
|
if (error.response) {
|
||||||
|
const { status, data } = error.response;
|
||||||
|
const errorData = (data as any)?.error || {};
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 401:
|
||||||
|
throw new AuthenticationError(errorData.message || 'Authentication failed');
|
||||||
|
case 404:
|
||||||
|
throw new NotFoundError(errorData.message || 'Resource not found');
|
||||||
|
case 422:
|
||||||
|
throw new ValidationError(errorData.message || 'Validation failed', errorData.param);
|
||||||
|
default:
|
||||||
|
throw new FetcherPayError(
|
||||||
|
errorData.message || 'An error occurred',
|
||||||
|
errorData.type || 'api_error',
|
||||||
|
status,
|
||||||
|
errorData.param,
|
||||||
|
errorData.code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize API clients
|
||||||
|
this.payments = new PaymentsClient(this.http);
|
||||||
|
this.ledger = new LedgerClient(this.http);
|
||||||
|
this.paymentMethods = new PaymentMethodsClient(this.http);
|
||||||
|
this.webhooks = new WebhooksClient(this.http);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify webhook signature
|
||||||
|
*/
|
||||||
|
verifyWebhookSignature(payload: string, signature: string, secret: string): boolean {
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const expected = crypto
|
||||||
|
.createHmac('sha256', secret)
|
||||||
|
.update(payload)
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
|
try {
|
||||||
|
return crypto.timingSafeEqual(
|
||||||
|
Buffer.from(signature),
|
||||||
|
Buffer.from(expected)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FetcherPay;
|
||||||
28
src/index.ts
Normal file
28
src/index.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay Node.js SDK
|
||||||
|
* One API. Every Rail.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* import { FetcherPay } from '@fetcherpay/node';
|
||||||
|
*
|
||||||
|
* const client = new FetcherPay({
|
||||||
|
* apiKey: 'fp_test_your_key',
|
||||||
|
* environment: 'sandbox'
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* const payment = await client.payments.create({
|
||||||
|
* amount: 10000,
|
||||||
|
* currency: 'USD',
|
||||||
|
* source: { payment_method_id: 'pm_123' },
|
||||||
|
* destination: { payment_method_id: 'pm_456' }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { FetcherPay } from './client';
|
||||||
|
export { PaymentsClient } from './api/payments';
|
||||||
|
export { LedgerClient } from './api/ledger';
|
||||||
|
export { PaymentMethodsClient } from './api/payment-methods';
|
||||||
|
export { WebhooksClient } from './api/webhooks';
|
||||||
|
export * from './types';
|
||||||
228
src/types/index.ts
Normal file
228
src/types/index.ts
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
/**
|
||||||
|
* FetcherPay SDK Types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface FetcherPayConfig {
|
||||||
|
apiKey: string;
|
||||||
|
environment?: 'sandbox' | 'production';
|
||||||
|
baseUrl?: string;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Payment {
|
||||||
|
id: string;
|
||||||
|
object: 'payment';
|
||||||
|
status: 'pending' | 'authorized' | 'processing' | 'settled' | 'failed' | 'cancelled' | 'refunded' | 'partially_refunded';
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
rail: string;
|
||||||
|
rail_selected: string;
|
||||||
|
description?: string;
|
||||||
|
source: PaymentSource;
|
||||||
|
destination: PaymentDestination;
|
||||||
|
fee?: Fee;
|
||||||
|
timeline: TimelineEvent[];
|
||||||
|
ledger_entry_ids: string[];
|
||||||
|
refunds: Refund[];
|
||||||
|
idempotency_key?: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaymentSource {
|
||||||
|
payment_method_id: string;
|
||||||
|
name?: string | null;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaymentDestination {
|
||||||
|
payment_method_id: string;
|
||||||
|
name?: string | null;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Fee {
|
||||||
|
amount: number;
|
||||||
|
rate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimelineEvent {
|
||||||
|
status: string;
|
||||||
|
timestamp: string;
|
||||||
|
detail: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Refund {
|
||||||
|
id: string;
|
||||||
|
payment_id: string;
|
||||||
|
amount: number;
|
||||||
|
reason?: string | null;
|
||||||
|
status: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePaymentRequest {
|
||||||
|
amount: number;
|
||||||
|
currency?: string;
|
||||||
|
rail?: 'auto' | 'ach' | 'rtp' | 'card' | 'crypto';
|
||||||
|
rail_fallback_order?: string[];
|
||||||
|
description?: string;
|
||||||
|
source: PaymentSource;
|
||||||
|
destination: PaymentDestination;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaymentMethod {
|
||||||
|
id: string;
|
||||||
|
object: 'payment_method';
|
||||||
|
type: 'bank_account' | 'card' | 'usdc_wallet';
|
||||||
|
status: 'active' | 'inactive' | 'verification_required';
|
||||||
|
bank_account?: BankAccount;
|
||||||
|
card?: Card;
|
||||||
|
usdc_wallet?: UsdcWallet;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BankAccount {
|
||||||
|
account_type: 'checking' | 'savings';
|
||||||
|
bank_name?: string;
|
||||||
|
routing_number_last4: string;
|
||||||
|
account_number_last4: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Card {
|
||||||
|
brand: string;
|
||||||
|
last4: string;
|
||||||
|
exp_month: number;
|
||||||
|
exp_year: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsdcWallet {
|
||||||
|
address: string;
|
||||||
|
network: 'ethereum' | 'polygon';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePaymentMethodRequest {
|
||||||
|
type: 'bank_account' | 'card' | 'usdc_wallet';
|
||||||
|
bank_account?: {
|
||||||
|
account_number: string;
|
||||||
|
routing_number: string;
|
||||||
|
account_type: 'checking' | 'savings';
|
||||||
|
};
|
||||||
|
card?: {
|
||||||
|
number: string;
|
||||||
|
exp_month: number;
|
||||||
|
exp_year: number;
|
||||||
|
cvc: string;
|
||||||
|
};
|
||||||
|
usdc_wallet?: {
|
||||||
|
address: string;
|
||||||
|
network: string;
|
||||||
|
};
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LedgerAccount {
|
||||||
|
id: string;
|
||||||
|
object: 'ledger_account';
|
||||||
|
name: string;
|
||||||
|
type: 'asset' | 'liability' | 'revenue' | 'expense' | 'equity';
|
||||||
|
currency: string;
|
||||||
|
balance: {
|
||||||
|
pending: number;
|
||||||
|
posted: number;
|
||||||
|
available: number;
|
||||||
|
};
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LedgerEntry {
|
||||||
|
id: string;
|
||||||
|
object: 'ledger_entry';
|
||||||
|
journal_id: string;
|
||||||
|
account_id: string;
|
||||||
|
payment_id?: string;
|
||||||
|
entry_type: 'debit' | 'credit';
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
status: 'pending' | 'posted';
|
||||||
|
description?: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebhookEndpoint {
|
||||||
|
id: string;
|
||||||
|
object: 'webhook_endpoint';
|
||||||
|
url: string;
|
||||||
|
events: string[];
|
||||||
|
status: 'active' | 'disabled';
|
||||||
|
secret: string;
|
||||||
|
metadata: Record<string, any>;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateWebhookRequest {
|
||||||
|
url: string;
|
||||||
|
events?: string[];
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebhookEvent {
|
||||||
|
id: string;
|
||||||
|
object: 'event';
|
||||||
|
type: string;
|
||||||
|
created_at: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListResponse<T> {
|
||||||
|
data: T[];
|
||||||
|
has_more: boolean;
|
||||||
|
next_cursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginationParams {
|
||||||
|
cursor?: string;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FilterParams {
|
||||||
|
created_after?: string;
|
||||||
|
created_before?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FetcherPayError extends Error {
|
||||||
|
constructor(
|
||||||
|
message: string,
|
||||||
|
public type: string,
|
||||||
|
public statusCode?: number,
|
||||||
|
public param?: string | null,
|
||||||
|
public code?: string | null
|
||||||
|
) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'FetcherPayError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AuthenticationError extends FetcherPayError {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message, 'authentication_error', 401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ValidationError extends FetcherPayError {
|
||||||
|
constructor(message: string, param?: string) {
|
||||||
|
super(message, 'validation_error', 422, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NotFoundError extends FetcherPayError {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message, 'not_found', 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"declaration": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": false,
|
||||||
|
"inlineSourceMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"strictPropertyInitialization": false,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user