@profullstack/coinpay 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/coinpay.js +96 -0
- package/package.json +5 -1
- package/src/card-payments.js +298 -0
- package/src/client.js +163 -0
- package/src/reputation.d.ts +17 -0
- package/src/reputation.js +53 -0
package/bin/coinpay.js
CHANGED
|
@@ -227,6 +227,10 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
227
227
|
badge [did] Get embeddable reputation badge URL
|
|
228
228
|
verify <id> Verify a credential
|
|
229
229
|
revocations List revoked credentials
|
|
230
|
+
issuer register Register platform issuer (--name, --domain)
|
|
231
|
+
issuer list List your platform issuers
|
|
232
|
+
issuer rotate Rotate issuer API key (--id)
|
|
233
|
+
issuer deactivate Deactivate an issuer (--id)
|
|
230
234
|
|
|
231
235
|
${colors.bright}webhook${colors.reset}
|
|
232
236
|
logs <business-id> Get webhook logs
|
|
@@ -1863,6 +1867,98 @@ async function handleReputation(subcommand, args, flags) {
|
|
|
1863
1867
|
break;
|
|
1864
1868
|
}
|
|
1865
1869
|
|
|
1870
|
+
case 'issuer': {
|
|
1871
|
+
const issuerSubcommand = args[0];
|
|
1872
|
+
const client = createClient();
|
|
1873
|
+
|
|
1874
|
+
switch (issuerSubcommand) {
|
|
1875
|
+
case 'register': {
|
|
1876
|
+
const name = flags.name;
|
|
1877
|
+
const domain = flags.domain;
|
|
1878
|
+
if (!name || !domain) {
|
|
1879
|
+
print.error('Required: --name <name> --domain <domain>');
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const { registerPlatformIssuer } = await import('../src/reputation.js');
|
|
1883
|
+
const result = await registerPlatformIssuer(client, { name, domain, did: flags.did });
|
|
1884
|
+
|
|
1885
|
+
if (result.success) {
|
|
1886
|
+
print.success(`Issuer registered: ${result.issuer.name}`);
|
|
1887
|
+
print.info(` ID: ${result.issuer.id}`);
|
|
1888
|
+
print.info(` DID: ${result.issuer.did}`);
|
|
1889
|
+
print.info(` Domain: ${result.issuer.domain}`);
|
|
1890
|
+
console.log(`\n ${colors.bright}${colors.yellow}⚠️ API Key (shown only once):${colors.reset}`);
|
|
1891
|
+
console.log(` ${colors.yellow}${result.api_key}${colors.reset}\n`);
|
|
1892
|
+
} else {
|
|
1893
|
+
print.error(result.error || 'Registration failed');
|
|
1894
|
+
}
|
|
1895
|
+
if (flags.json) print.json(result);
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
case 'list': {
|
|
1900
|
+
const { listPlatformIssuers } = await import('../src/reputation.js');
|
|
1901
|
+
const result = await listPlatformIssuers(client);
|
|
1902
|
+
|
|
1903
|
+
if (result.success) {
|
|
1904
|
+
print.info(`Platform issuers (${result.issuers.length}):`);
|
|
1905
|
+
for (const iss of result.issuers) {
|
|
1906
|
+
const status = iss.active ? `${colors.green}active${colors.reset}` : `${colors.red}inactive${colors.reset}`;
|
|
1907
|
+
console.log(` ${iss.id} | ${iss.name} | ${iss.domain} | ${status} | key: ${iss.api_key || 'none'}`);
|
|
1908
|
+
}
|
|
1909
|
+
} else {
|
|
1910
|
+
print.error(result.error || 'Failed to list issuers');
|
|
1911
|
+
}
|
|
1912
|
+
if (flags.json) print.json(result);
|
|
1913
|
+
break;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
case 'rotate': {
|
|
1917
|
+
const id = flags.id || args[1];
|
|
1918
|
+
if (!id) {
|
|
1919
|
+
print.error('Required: --id <issuer-id>');
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
const { rotatePlatformApiKey } = await import('../src/reputation.js');
|
|
1923
|
+
const result = await rotatePlatformApiKey(client, id);
|
|
1924
|
+
|
|
1925
|
+
if (result.success) {
|
|
1926
|
+
print.success(`API key rotated for: ${result.issuer.name}`);
|
|
1927
|
+
console.log(`\n ${colors.bright}${colors.yellow}⚠️ New API Key (shown only once):${colors.reset}`);
|
|
1928
|
+
console.log(` ${colors.yellow}${result.api_key}${colors.reset}\n`);
|
|
1929
|
+
} else {
|
|
1930
|
+
print.error(result.error || 'Rotation failed');
|
|
1931
|
+
}
|
|
1932
|
+
if (flags.json) print.json(result);
|
|
1933
|
+
break;
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
case 'deactivate': {
|
|
1937
|
+
const id = flags.id || args[1];
|
|
1938
|
+
if (!id) {
|
|
1939
|
+
print.error('Required: --id <issuer-id>');
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
const { deactivatePlatformIssuer } = await import('../src/reputation.js');
|
|
1943
|
+
const result = await deactivatePlatformIssuer(client, id);
|
|
1944
|
+
|
|
1945
|
+
if (result.success) {
|
|
1946
|
+
print.success(`Issuer deactivated: ${result.issuer.name}`);
|
|
1947
|
+
} else {
|
|
1948
|
+
print.error(result.error || 'Deactivation failed');
|
|
1949
|
+
}
|
|
1950
|
+
if (flags.json) print.json(result);
|
|
1951
|
+
break;
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
default:
|
|
1955
|
+
print.error(`Unknown issuer command: ${issuerSubcommand}`);
|
|
1956
|
+
print.info('Available: register, list, rotate, deactivate');
|
|
1957
|
+
process.exit(1);
|
|
1958
|
+
}
|
|
1959
|
+
break;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1866
1962
|
case 'badge': {
|
|
1867
1963
|
const did = args[0];
|
|
1868
1964
|
if (!did) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/coinpay",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"import": "./src/payments.js",
|
|
18
18
|
"types": "./src/payments.d.ts"
|
|
19
19
|
},
|
|
20
|
+
"./card-payments": {
|
|
21
|
+
"import": "./src/card-payments.js",
|
|
22
|
+
"types": "./src/card-payments.d.ts"
|
|
23
|
+
},
|
|
20
24
|
"./webhooks": {
|
|
21
25
|
"import": "./src/webhooks.js",
|
|
22
26
|
"types": "./src/webhooks.d.ts"
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoinPay Card Payments - Convenience functions for Stripe integration
|
|
3
|
+
*
|
|
4
|
+
* This module provides high-level convenience functions for working with
|
|
5
|
+
* card payments through Stripe Connect, similar to the payments.js module.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Quick card payment creation with sensible defaults
|
|
10
|
+
*
|
|
11
|
+
* @param {import('./client.js').CoinPayClient} client - CoinPay client instance
|
|
12
|
+
* @param {string} businessId - Business ID
|
|
13
|
+
* @param {number} amountUSD - Amount in USD (will be converted to cents)
|
|
14
|
+
* @param {string} description - Payment description
|
|
15
|
+
* @param {Object} [options] - Additional options
|
|
16
|
+
* @param {Object} [options.metadata] - Custom metadata
|
|
17
|
+
* @param {string} [options.successUrl] - Success redirect URL
|
|
18
|
+
* @param {string} [options.cancelUrl] - Cancel redirect URL
|
|
19
|
+
* @param {boolean} [options.escrowMode=false] - Enable escrow mode
|
|
20
|
+
* @returns {Promise<Object>} Payment session with checkout URL
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* import { createQuickCardPayment } from '@profullstack/coinpay/card-payments';
|
|
24
|
+
*
|
|
25
|
+
* const payment = await createQuickCardPayment(client, 'business-id', 50, 'Order #123', {
|
|
26
|
+
* metadata: { orderId: '123' },
|
|
27
|
+
* escrowMode: true
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Redirect customer to: payment.checkout_url
|
|
31
|
+
*/
|
|
32
|
+
export async function createQuickCardPayment(client, businessId, amountUSD, description, options = {}) {
|
|
33
|
+
const {
|
|
34
|
+
metadata = {},
|
|
35
|
+
successUrl,
|
|
36
|
+
cancelUrl,
|
|
37
|
+
escrowMode = false,
|
|
38
|
+
} = options;
|
|
39
|
+
|
|
40
|
+
// Convert USD to cents
|
|
41
|
+
const amountCents = Math.round(amountUSD * 100);
|
|
42
|
+
|
|
43
|
+
return client.createCardPayment({
|
|
44
|
+
businessId,
|
|
45
|
+
amount: amountCents,
|
|
46
|
+
currency: 'usd',
|
|
47
|
+
description,
|
|
48
|
+
metadata,
|
|
49
|
+
successUrl,
|
|
50
|
+
cancelUrl,
|
|
51
|
+
escrowMode,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Wait for merchant to complete Stripe onboarding
|
|
57
|
+
*
|
|
58
|
+
* Polls the Stripe account status until onboarding is complete.
|
|
59
|
+
* Useful for integration flows where you need to wait for merchant setup.
|
|
60
|
+
*
|
|
61
|
+
* @param {import('./client.js').CoinPayClient} client - CoinPay client instance
|
|
62
|
+
* @param {string} businessId - Business ID
|
|
63
|
+
* @param {Object} [options] - Polling options
|
|
64
|
+
* @param {number} [options.intervalMs=5000] - Polling interval in ms
|
|
65
|
+
* @param {number} [options.timeoutMs=300000] - Timeout in ms (default: 5 minutes)
|
|
66
|
+
* @param {Function} [options.onStatusChange] - Callback for status changes
|
|
67
|
+
* @returns {Promise<Object>} Final account status when onboarding complete
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const accountStatus = await waitForStripeOnboarding(client, 'business-id', {
|
|
71
|
+
* onStatusChange: (status) => {
|
|
72
|
+
* console.log(`Onboarding status: ${JSON.stringify(status)}`);
|
|
73
|
+
* }
|
|
74
|
+
* });
|
|
75
|
+
*/
|
|
76
|
+
export async function waitForStripeOnboarding(client, businessId, options = {}) {
|
|
77
|
+
const {
|
|
78
|
+
intervalMs = 5000,
|
|
79
|
+
timeoutMs = 300000, // 5 minutes
|
|
80
|
+
onStatusChange,
|
|
81
|
+
} = options;
|
|
82
|
+
|
|
83
|
+
const startTime = Date.now();
|
|
84
|
+
|
|
85
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
86
|
+
const status = await client.getStripeAccountStatus(businessId);
|
|
87
|
+
|
|
88
|
+
if (onStatusChange) {
|
|
89
|
+
onStatusChange(status);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (status.onboarding_complete) {
|
|
93
|
+
return status;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Wait before next poll
|
|
97
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
throw new Error(`Stripe onboarding timeout after ${timeoutMs}ms`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Create payment with automatic merchant onboarding check
|
|
105
|
+
*
|
|
106
|
+
* Checks if merchant has completed Stripe onboarding first, and provides
|
|
107
|
+
* helpful error messages if not. Prevents failed payment attempts.
|
|
108
|
+
*
|
|
109
|
+
* @param {import('./client.js').CoinPayClient} client - CoinPay client instance
|
|
110
|
+
* @param {Object} params - Payment parameters (same as createCardPayment)
|
|
111
|
+
* @returns {Promise<Object>} Payment session or onboarding info if incomplete
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const result = await createCardPaymentWithOnboardingCheck(client, {
|
|
115
|
+
* businessId: 'business-id',
|
|
116
|
+
* amount: 5000,
|
|
117
|
+
* description: 'Order #123'
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* if (result.requires_onboarding) {
|
|
121
|
+
* // Redirect merchant to result.onboarding_url
|
|
122
|
+
* } else {
|
|
123
|
+
* // Redirect customer to result.checkout_url
|
|
124
|
+
* }
|
|
125
|
+
*/
|
|
126
|
+
export async function createCardPaymentWithOnboardingCheck(client, params) {
|
|
127
|
+
try {
|
|
128
|
+
// Check onboarding status first
|
|
129
|
+
const status = await client.getStripeAccountStatus(params.businessId);
|
|
130
|
+
|
|
131
|
+
if (!status.onboarding_complete) {
|
|
132
|
+
// Generate onboarding link if needed
|
|
133
|
+
const onboarding = await client.createStripeOnboardingLink(params.businessId);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
requires_onboarding: true,
|
|
137
|
+
onboarding_url: onboarding.onboarding_url,
|
|
138
|
+
status: status,
|
|
139
|
+
message: 'Merchant must complete Stripe onboarding before accepting card payments',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Onboarding complete, create payment
|
|
144
|
+
const payment = await client.createCardPayment(params);
|
|
145
|
+
return {
|
|
146
|
+
requires_onboarding: false,
|
|
147
|
+
...payment,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error.status === 404) {
|
|
152
|
+
// No Stripe account exists, need onboarding
|
|
153
|
+
const onboarding = await client.createStripeOnboardingLink(params.businessId);
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
requires_onboarding: true,
|
|
157
|
+
onboarding_url: onboarding.onboarding_url,
|
|
158
|
+
status: null,
|
|
159
|
+
message: 'Merchant needs to complete Stripe onboarding',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get payment method support status
|
|
168
|
+
*
|
|
169
|
+
* Returns which payment methods are available for a merchant.
|
|
170
|
+
* Helps with conditional UI rendering.
|
|
171
|
+
*
|
|
172
|
+
* @param {import('./client.js').CoinPayClient} client - CoinPay client instance
|
|
173
|
+
* @param {string} businessId - Business ID
|
|
174
|
+
* @returns {Promise<Object>} Available payment methods
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* const support = await getPaymentMethodSupport(client, 'business-id');
|
|
178
|
+
* console.log(support);
|
|
179
|
+
* // {
|
|
180
|
+
* // crypto: true,
|
|
181
|
+
* // cards: true,
|
|
182
|
+
* // escrow: true,
|
|
183
|
+
* // stripe_onboarding_complete: true
|
|
184
|
+
* // }
|
|
185
|
+
*/
|
|
186
|
+
export async function getPaymentMethodSupport(client, businessId) {
|
|
187
|
+
try {
|
|
188
|
+
// Check if business exists (crypto payments always work)
|
|
189
|
+
await client.getBusiness(businessId);
|
|
190
|
+
|
|
191
|
+
let cardSupport = false;
|
|
192
|
+
let stripeOnboardingComplete = false;
|
|
193
|
+
|
|
194
|
+
// Check Stripe status
|
|
195
|
+
try {
|
|
196
|
+
const stripeStatus = await client.getStripeAccountStatus(businessId);
|
|
197
|
+
cardSupport = stripeStatus.onboarding_complete;
|
|
198
|
+
stripeOnboardingComplete = stripeStatus.onboarding_complete;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
// No Stripe account = no card support yet
|
|
201
|
+
cardSupport = false;
|
|
202
|
+
stripeOnboardingComplete = false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
crypto: true, // Always available
|
|
207
|
+
cards: cardSupport,
|
|
208
|
+
escrow: cardSupport, // Card escrow requires Stripe
|
|
209
|
+
stripe_onboarding_complete: stripeOnboardingComplete,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (error.status === 404) {
|
|
214
|
+
return {
|
|
215
|
+
crypto: false,
|
|
216
|
+
cards: false,
|
|
217
|
+
escrow: false,
|
|
218
|
+
stripe_onboarding_complete: false,
|
|
219
|
+
error: 'Business not found',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Format amount for display
|
|
228
|
+
*
|
|
229
|
+
* Converts cents to dollar amount with proper formatting.
|
|
230
|
+
*
|
|
231
|
+
* @param {number} amountCents - Amount in cents
|
|
232
|
+
* @param {string} [currency='USD'] - Currency code
|
|
233
|
+
* @returns {string} Formatted amount string
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* formatCardAmount(5000); // "$50.00"
|
|
237
|
+
* formatCardAmount(5050); // "$50.50"
|
|
238
|
+
* formatCardAmount(500, 'EUR'); // "€5.00"
|
|
239
|
+
*/
|
|
240
|
+
export function formatCardAmount(amountCents, currency = 'USD') {
|
|
241
|
+
const amount = amountCents / 100;
|
|
242
|
+
|
|
243
|
+
const formatters = {
|
|
244
|
+
USD: (amt) => `$${amt.toFixed(2)}`,
|
|
245
|
+
EUR: (amt) => `€${amt.toFixed(2)}`,
|
|
246
|
+
GBP: (amt) => `£${amt.toFixed(2)}`,
|
|
247
|
+
CAD: (amt) => `C$${amt.toFixed(2)}`,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const formatter = formatters[currency.toUpperCase()];
|
|
251
|
+
if (formatter) {
|
|
252
|
+
return formatter(amount);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Fallback for unknown currencies
|
|
256
|
+
return `${amount.toFixed(2)} ${currency.toUpperCase()}`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Calculate platform fees for card payments
|
|
261
|
+
*
|
|
262
|
+
* @param {number} amountCents - Payment amount in cents
|
|
263
|
+
* @param {string} tier - Merchant tier ('free' or 'pro')
|
|
264
|
+
* @returns {Object} Fee breakdown
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* const fees = calculateCardPaymentFees(5000, 'free');
|
|
268
|
+
* console.log(fees);
|
|
269
|
+
* // {
|
|
270
|
+
* // amount: 5000,
|
|
271
|
+
* // platformFee: 50,
|
|
272
|
+
* // platformFeePercent: 1,
|
|
273
|
+
* // merchantReceives: 4950 // before Stripe fees
|
|
274
|
+
* // }
|
|
275
|
+
*/
|
|
276
|
+
export function calculateCardPaymentFees(amountCents, tier = 'free') {
|
|
277
|
+
const platformFeePercent = tier === 'pro' ? 0.5 : 1.0; // 0.5% or 1%
|
|
278
|
+
const platformFeeCents = Math.round(amountCents * (platformFeePercent / 100));
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
amount: amountCents,
|
|
282
|
+
platformFee: platformFeeCents,
|
|
283
|
+
platformFeePercent,
|
|
284
|
+
merchantReceives: amountCents - platformFeeCents, // Before Stripe processing fees
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Default export with all convenience functions
|
|
290
|
+
*/
|
|
291
|
+
export default {
|
|
292
|
+
createQuickCardPayment,
|
|
293
|
+
waitForStripeOnboarding,
|
|
294
|
+
createCardPaymentWithOnboardingCheck,
|
|
295
|
+
getPaymentMethodSupport,
|
|
296
|
+
formatCardAmount,
|
|
297
|
+
calculateCardPaymentFees,
|
|
298
|
+
};
|
package/src/client.js
CHANGED
|
@@ -522,6 +522,169 @@ export class CoinPayClient {
|
|
|
522
522
|
const { authenticateEscrow } = await import('./escrow.js');
|
|
523
523
|
return authenticateEscrow(this, escrowId, token);
|
|
524
524
|
}
|
|
525
|
+
|
|
526
|
+
// ── Stripe Card Payment Methods ────────────────────────
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Create a card payment using Stripe
|
|
530
|
+
*
|
|
531
|
+
* Creates a card payment session through Stripe Connect. Returns a checkout URL
|
|
532
|
+
* that customers can use to pay with their credit/debit card.
|
|
533
|
+
*
|
|
534
|
+
* @param {Object} params - Payment parameters
|
|
535
|
+
* @param {string} params.businessId - Business ID (merchant must have completed Stripe onboarding)
|
|
536
|
+
* @param {number} params.amount - Amount in cents (e.g., 5000 = $50.00)
|
|
537
|
+
* @param {string} [params.currency='usd'] - Currency code (usd, eur, etc.)
|
|
538
|
+
* @param {string} [params.description] - Payment description
|
|
539
|
+
* @param {Object} [params.metadata] - Custom metadata
|
|
540
|
+
* @param {string} [params.successUrl] - URL to redirect on successful payment
|
|
541
|
+
* @param {string} [params.cancelUrl] - URL to redirect on payment cancellation
|
|
542
|
+
* @param {boolean} [params.escrowMode=false] - Whether to use escrow mode (holds funds until release)
|
|
543
|
+
* @returns {Promise<Object>} Payment session with checkout URL
|
|
544
|
+
*
|
|
545
|
+
* @example
|
|
546
|
+
* // Create a $50 card payment
|
|
547
|
+
* const payment = await client.createCardPayment({
|
|
548
|
+
* businessId: 'your-business-id',
|
|
549
|
+
* amount: 5000, // $50.00 in cents
|
|
550
|
+
* currency: 'usd',
|
|
551
|
+
* description: 'Order #12345',
|
|
552
|
+
* metadata: { orderId: '12345' },
|
|
553
|
+
* successUrl: 'https://yourdomain.com/success',
|
|
554
|
+
* cancelUrl: 'https://yourdomain.com/cancel'
|
|
555
|
+
* });
|
|
556
|
+
*
|
|
557
|
+
* // Redirect customer to payment.checkout_url
|
|
558
|
+
*/
|
|
559
|
+
async createCardPayment({
|
|
560
|
+
businessId,
|
|
561
|
+
amount,
|
|
562
|
+
currency = 'usd',
|
|
563
|
+
description,
|
|
564
|
+
metadata,
|
|
565
|
+
successUrl,
|
|
566
|
+
cancelUrl,
|
|
567
|
+
escrowMode = false
|
|
568
|
+
}) {
|
|
569
|
+
return this.request('/stripe/payments/create', {
|
|
570
|
+
method: 'POST',
|
|
571
|
+
body: JSON.stringify({
|
|
572
|
+
businessId,
|
|
573
|
+
amount,
|
|
574
|
+
currency,
|
|
575
|
+
description,
|
|
576
|
+
metadata,
|
|
577
|
+
successUrl,
|
|
578
|
+
cancelUrl,
|
|
579
|
+
escrowMode
|
|
580
|
+
}),
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Get Stripe account onboarding status
|
|
586
|
+
*
|
|
587
|
+
* Checks whether a merchant has completed Stripe Connect onboarding
|
|
588
|
+
* and is able to accept card payments.
|
|
589
|
+
*
|
|
590
|
+
* @param {string} businessId - Business ID
|
|
591
|
+
* @returns {Promise<Object>} Account status and capabilities
|
|
592
|
+
*
|
|
593
|
+
* @example
|
|
594
|
+
* const status = await client.getStripeAccountStatus('business-id');
|
|
595
|
+
* if (status.onboarding_complete) {
|
|
596
|
+
* console.log('Merchant can accept card payments');
|
|
597
|
+
* }
|
|
598
|
+
*/
|
|
599
|
+
async getStripeAccountStatus(businessId) {
|
|
600
|
+
return this.request(`/stripe/connect/status/${businessId}`);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Create Stripe Connect onboarding link
|
|
605
|
+
*
|
|
606
|
+
* Generates a Stripe Express onboarding link for a merchant.
|
|
607
|
+
* The merchant must complete this onboarding before they can accept card payments.
|
|
608
|
+
*
|
|
609
|
+
* @param {string} businessId - Business ID
|
|
610
|
+
* @param {Object} [params] - Optional parameters
|
|
611
|
+
* @param {string} [params.email] - Merchant email (pre-fills onboarding form)
|
|
612
|
+
* @param {string} [params.country='US'] - Country code (US, CA, GB, etc.)
|
|
613
|
+
* @returns {Promise<Object>} Onboarding link and account ID
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* const onboarding = await client.createStripeOnboardingLink('business-id', {
|
|
617
|
+
* email: 'merchant@example.com',
|
|
618
|
+
* country: 'US'
|
|
619
|
+
* });
|
|
620
|
+
*
|
|
621
|
+
* // Redirect merchant to onboarding.onboarding_url
|
|
622
|
+
*/
|
|
623
|
+
async createStripeOnboardingLink(businessId, params = {}) {
|
|
624
|
+
return this.request('/stripe/connect/onboard', {
|
|
625
|
+
method: 'POST',
|
|
626
|
+
body: JSON.stringify({
|
|
627
|
+
businessId,
|
|
628
|
+
...params
|
|
629
|
+
}),
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Release card escrow funds to merchant
|
|
635
|
+
*
|
|
636
|
+
* Releases funds held in card escrow mode to the merchant's Stripe account.
|
|
637
|
+
* Only works for payments created with escrowMode: true.
|
|
638
|
+
*
|
|
639
|
+
* @param {string} escrowId - Escrow ID (returned from escrow payment creation)
|
|
640
|
+
* @param {string} [reason] - Reason for release
|
|
641
|
+
* @returns {Promise<Object>} Release confirmation with transfer details
|
|
642
|
+
*
|
|
643
|
+
* @example
|
|
644
|
+
* const release = await client.releaseCardEscrow('escrow-id', 'Work completed');
|
|
645
|
+
* console.log(`Released $${release.amount_transferred / 100} to merchant`);
|
|
646
|
+
*/
|
|
647
|
+
async releaseCardEscrow(escrowId, reason) {
|
|
648
|
+
return this.request('/stripe/escrow/release', {
|
|
649
|
+
method: 'POST',
|
|
650
|
+
body: JSON.stringify({
|
|
651
|
+
escrowId,
|
|
652
|
+
reason
|
|
653
|
+
}),
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Refund a card payment
|
|
659
|
+
*
|
|
660
|
+
* Creates a refund for a card payment. Works for both gateway and escrow mode payments.
|
|
661
|
+
* For escrow payments, refunds from held funds. For gateway payments, refunds from merchant account.
|
|
662
|
+
*
|
|
663
|
+
* @param {string} paymentId - Payment intent ID or escrow ID
|
|
664
|
+
* @param {Object} [params] - Optional parameters
|
|
665
|
+
* @param {number} [params.amount] - Refund amount in cents (partial refund). Omit for full refund.
|
|
666
|
+
* @param {string} [params.reason] - Reason for refund
|
|
667
|
+
* @returns {Promise<Object>} Refund confirmation
|
|
668
|
+
*
|
|
669
|
+
* @example
|
|
670
|
+
* // Full refund
|
|
671
|
+
* const refund = await client.refundCardPayment('payment-id');
|
|
672
|
+
*
|
|
673
|
+
* // Partial refund
|
|
674
|
+
* const partialRefund = await client.refundCardPayment('payment-id', {
|
|
675
|
+
* amount: 2500, // $25.00 refund
|
|
676
|
+
* reason: 'Customer complaint'
|
|
677
|
+
* });
|
|
678
|
+
*/
|
|
679
|
+
async refundCardPayment(paymentId, params = {}) {
|
|
680
|
+
return this.request('/stripe/escrow/refund', {
|
|
681
|
+
method: 'POST',
|
|
682
|
+
body: JSON.stringify({
|
|
683
|
+
escrowId: paymentId, // API expects escrowId param
|
|
684
|
+
...params
|
|
685
|
+
}),
|
|
686
|
+
});
|
|
687
|
+
}
|
|
525
688
|
}
|
|
526
689
|
|
|
527
690
|
export default CoinPayClient;
|
package/src/reputation.d.ts
CHANGED
|
@@ -113,3 +113,20 @@ export interface DidInfo {
|
|
|
113
113
|
export function getMyDid(client: CoinPayClient): Promise<DidInfo>;
|
|
114
114
|
export function claimDid(client: CoinPayClient): Promise<DidInfo>;
|
|
115
115
|
export function linkDid(client: CoinPayClient, params: { did: string; publicKey: string; signature: string }): Promise<DidInfo>;
|
|
116
|
+
|
|
117
|
+
// Platform Issuer Self-Service
|
|
118
|
+
|
|
119
|
+
export interface PlatformIssuer {
|
|
120
|
+
id: string;
|
|
121
|
+
did: string;
|
|
122
|
+
name: string;
|
|
123
|
+
domain: string;
|
|
124
|
+
active: boolean;
|
|
125
|
+
api_key: string | null;
|
|
126
|
+
created_at: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function registerPlatformIssuer(client: CoinPayClient, params: { name: string; domain: string; did?: string }): Promise<{ success: boolean; issuer: PlatformIssuer; api_key: string }>;
|
|
130
|
+
export function listPlatformIssuers(client: CoinPayClient): Promise<{ success: boolean; issuers: PlatformIssuer[] }>;
|
|
131
|
+
export function rotatePlatformApiKey(client: CoinPayClient, issuerId: string): Promise<{ success: boolean; issuer: PlatformIssuer; api_key: string }>;
|
|
132
|
+
export function deactivatePlatformIssuer(client: CoinPayClient, issuerId: string): Promise<{ success: boolean; issuer: PlatformIssuer }>;
|
package/src/reputation.js
CHANGED
|
@@ -180,3 +180,56 @@ export async function getTrustProfile(client, agentDid) {
|
|
|
180
180
|
export function getBadgeUrl(baseUrl, did) {
|
|
181
181
|
return `${baseUrl}/api/reputation/badge/${encodeURIComponent(did)}`;
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
// ═══════════════════════════════════════════════════════════
|
|
185
|
+
// Platform Issuer Self-Service
|
|
186
|
+
// ═══════════════════════════════════════════════════════════
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Register a new platform issuer
|
|
190
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
191
|
+
* @param {Object} params
|
|
192
|
+
* @param {string} params.name - Issuer name (alphanumeric, dots, hyphens, underscores)
|
|
193
|
+
* @param {string} params.domain - Issuer domain
|
|
194
|
+
* @param {string} [params.did] - Optional DID (auto-generated from domain if omitted)
|
|
195
|
+
* @returns {Promise<Object>} { success, issuer, api_key }
|
|
196
|
+
*/
|
|
197
|
+
export async function registerPlatformIssuer(client, { name, domain, did }) {
|
|
198
|
+
return client.request('/reputation/issuers', {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
body: JSON.stringify({ name, domain, did }),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* List merchant's registered platform issuers (keys masked)
|
|
206
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
207
|
+
* @returns {Promise<Object>} { success, issuers }
|
|
208
|
+
*/
|
|
209
|
+
export async function listPlatformIssuers(client) {
|
|
210
|
+
return client.request('/reputation/issuers');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Rotate a platform issuer's API key
|
|
215
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
216
|
+
* @param {string} issuerId - The issuer ID
|
|
217
|
+
* @returns {Promise<Object>} { success, issuer, api_key }
|
|
218
|
+
*/
|
|
219
|
+
export async function rotatePlatformApiKey(client, issuerId) {
|
|
220
|
+
return client.request(`/reputation/issuers/${issuerId}/rotate`, {
|
|
221
|
+
method: 'POST',
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Deactivate a platform issuer (soft delete)
|
|
227
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
228
|
+
* @param {string} issuerId - The issuer ID
|
|
229
|
+
* @returns {Promise<Object>} { success, issuer }
|
|
230
|
+
*/
|
|
231
|
+
export async function deactivatePlatformIssuer(client, issuerId) {
|
|
232
|
+
return client.request(`/reputation/issuers/${issuerId}`, {
|
|
233
|
+
method: 'DELETE',
|
|
234
|
+
});
|
|
235
|
+
}
|