@puul/partner-sdk 1.0.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/index.d.mts +317 -21
- package/dist/index.d.ts +317 -21
- package/dist/index.js +136 -4
- package/dist/index.mjs +121 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -139,8 +139,20 @@ await puul.wallet.deposit({
|
|
|
139
139
|
currency: 'USDC',
|
|
140
140
|
idempotency_key: 'dep_unique_123',
|
|
141
141
|
});
|
|
142
|
+
|
|
143
|
+
// Withdraw from omnibus to configured bank/crypto destination
|
|
144
|
+
const withdrawal = await puul.wallet.withdraw({
|
|
145
|
+
amount: 500000, // $5,000 in minor units
|
|
146
|
+
currency: 'USDC',
|
|
147
|
+
method: 'bank', // or 'crypto'
|
|
148
|
+
});
|
|
149
|
+
// withdrawal.withdrawalId, withdrawal.status
|
|
142
150
|
```
|
|
143
151
|
|
|
152
|
+
> **Auto-Settlement:** If your `payout_method` is configured (via the admin dashboard),
|
|
153
|
+
> revenue share is automatically paid out after each market settlement. You don't need
|
|
154
|
+
> to call `withdraw()` manually — it happens at settlement time.
|
|
155
|
+
|
|
144
156
|
### Webhook Verification
|
|
145
157
|
|
|
146
158
|
```typescript
|
|
@@ -163,9 +175,16 @@ app.post('/webhooks/puul', express.raw({ type: '*/*' }), (req, res) => {
|
|
|
163
175
|
case 'prediction.settled':
|
|
164
176
|
console.log('Prediction settled:', event.data);
|
|
165
177
|
break;
|
|
178
|
+
case 'prediction.voided':
|
|
179
|
+
console.log('Prediction voided:', event.data);
|
|
180
|
+
// Handle refund — user gets full stake back
|
|
181
|
+
break;
|
|
166
182
|
case 'deposit.confirmed':
|
|
167
183
|
console.log('Deposit confirmed:', event.data);
|
|
168
184
|
break;
|
|
185
|
+
case 'withdrawal.completed':
|
|
186
|
+
console.log('Withdrawal completed:', event.data);
|
|
187
|
+
break;
|
|
169
188
|
}
|
|
170
189
|
|
|
171
190
|
res.status(200).send('OK');
|
package/dist/index.d.mts
CHANGED
|
@@ -33,22 +33,27 @@ interface MarketOutcome {
|
|
|
33
33
|
id: string;
|
|
34
34
|
slug: string;
|
|
35
35
|
label: string;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
display_order: number;
|
|
37
|
+
pool_amount: string;
|
|
38
|
+
predictor_count: number;
|
|
39
|
+
prediction_count: number;
|
|
40
40
|
}
|
|
41
41
|
interface Market {
|
|
42
42
|
id: string;
|
|
43
43
|
question: string;
|
|
44
|
-
description: string;
|
|
45
44
|
category: string;
|
|
45
|
+
image_url: string;
|
|
46
|
+
market_type: string;
|
|
46
47
|
status: string;
|
|
47
48
|
currency: string;
|
|
48
49
|
close_time: string;
|
|
49
50
|
freeze_at: string | null;
|
|
50
|
-
target_countries: string[];
|
|
51
51
|
outcomes: MarketOutcome[];
|
|
52
|
+
volume: number;
|
|
53
|
+
volume_currency: string;
|
|
54
|
+
predictor_count: number;
|
|
55
|
+
prediction_count: number;
|
|
56
|
+
created_at: string;
|
|
52
57
|
}
|
|
53
58
|
type PredictionStatus = 'OPEN' | 'WON' | 'LOST' | 'VOIDED';
|
|
54
59
|
type Currency = 'NGN' | 'USDC' | 'USDT' | 'KES' | 'GHS' | 'ZAR';
|
|
@@ -149,26 +154,238 @@ interface DepositParams {
|
|
|
149
154
|
idempotency_key: string;
|
|
150
155
|
reference?: string;
|
|
151
156
|
}
|
|
152
|
-
type
|
|
153
|
-
interface
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
type WithdrawMethod = 'bank' | 'crypto';
|
|
158
|
+
interface WithdrawParams {
|
|
159
|
+
/** Amount to withdraw in minor units (cents) */
|
|
160
|
+
amount: number;
|
|
161
|
+
/** Currency to withdraw. Defaults to USDC */
|
|
162
|
+
currency?: Currency;
|
|
163
|
+
/** Payout method: 'bank' for fiat, 'crypto' for on-chain */
|
|
164
|
+
method?: WithdrawMethod;
|
|
165
|
+
}
|
|
166
|
+
interface WithdrawResult {
|
|
167
|
+
withdrawalId: string;
|
|
168
|
+
partnerId: string;
|
|
169
|
+
amount: number;
|
|
170
|
+
currency: string;
|
|
171
|
+
method: WithdrawMethod;
|
|
172
|
+
payoutReference: string | null;
|
|
173
|
+
status: string;
|
|
174
|
+
}
|
|
175
|
+
type LotteryPoolType = 'winner_takes_all' | 'tiered';
|
|
176
|
+
type LotteryPoolFrequency = 'daily' | 'weekly' | 'monthly' | 'quarterly';
|
|
177
|
+
type LotteryPoolStatus = 'upcoming' | 'open' | 'drawing' | 'settled' | 'cancelled';
|
|
178
|
+
type LotteryEntryStatus = 'active' | 'won' | 'lost' | 'refunded';
|
|
179
|
+
interface PrizeTier {
|
|
180
|
+
/** 1-based rank (1 = first place) */
|
|
181
|
+
rank: number;
|
|
182
|
+
/** Percentage of distributable pool in basis points (5000 = 50%) */
|
|
183
|
+
pct: number;
|
|
184
|
+
}
|
|
185
|
+
interface LotteryPool {
|
|
186
|
+
id: string;
|
|
187
|
+
title: string;
|
|
188
|
+
description: string | null;
|
|
189
|
+
type: LotteryPoolType;
|
|
190
|
+
frequency: LotteryPoolFrequency;
|
|
191
|
+
status: LotteryPoolStatus;
|
|
192
|
+
ticket_price: string;
|
|
193
|
+
currency: string;
|
|
194
|
+
max_tickets: number | null;
|
|
195
|
+
max_tickets_per_user: number | null;
|
|
196
|
+
total_entries: number;
|
|
197
|
+
total_pool_amount: string;
|
|
198
|
+
opens_at: string;
|
|
199
|
+
draws_at: string;
|
|
200
|
+
drawn_at: string | null;
|
|
201
|
+
winning_numbers: number[];
|
|
202
|
+
prize_tiers: PrizeTier[];
|
|
203
|
+
takeout_rate_bps: number;
|
|
204
|
+
}
|
|
205
|
+
interface LotteryEntry {
|
|
206
|
+
id: string;
|
|
207
|
+
pool_id: string;
|
|
208
|
+
user_id: string | null;
|
|
209
|
+
user_external_id: string | null;
|
|
210
|
+
ticket_number: number;
|
|
211
|
+
amount_paid: string;
|
|
212
|
+
currency: string;
|
|
213
|
+
status: LotteryEntryStatus;
|
|
214
|
+
prize_amount: string | null;
|
|
215
|
+
prize_tier: number | null;
|
|
216
|
+
purchased_at: string;
|
|
217
|
+
}
|
|
218
|
+
interface LotteryEntriesResponse {
|
|
219
|
+
entries: LotteryEntry[];
|
|
220
|
+
total: number;
|
|
221
|
+
}
|
|
222
|
+
interface BuyTicketParams {
|
|
223
|
+
/** Puul user ID of the linked user */
|
|
224
|
+
userId: string;
|
|
225
|
+
/** Unique key to prevent duplicate purchases */
|
|
226
|
+
idempotencyKey: string;
|
|
227
|
+
/** Number of tickets (default: 1) */
|
|
228
|
+
quantity?: number;
|
|
229
|
+
/** Your external user ID (for tracking) */
|
|
230
|
+
userExternalId?: string;
|
|
231
|
+
}
|
|
232
|
+
interface BuyTicketResponse {
|
|
233
|
+
entries: LotteryEntry[];
|
|
234
|
+
}
|
|
235
|
+
interface LotteryDrawResult {
|
|
236
|
+
pool_id: string;
|
|
237
|
+
status: string;
|
|
238
|
+
drawn_at: string | null;
|
|
239
|
+
winning_numbers: number[];
|
|
240
|
+
total_pool_amount: string;
|
|
241
|
+
your_entries: Array<{
|
|
242
|
+
id: string;
|
|
243
|
+
ticket_number: number;
|
|
244
|
+
user_id: string | null;
|
|
245
|
+
user_external_id: string | null;
|
|
246
|
+
status: string;
|
|
247
|
+
prize_amount: string | null;
|
|
248
|
+
prize_tier: number | null;
|
|
249
|
+
}>;
|
|
250
|
+
your_winners: number;
|
|
251
|
+
your_total_winnings: number;
|
|
252
|
+
}
|
|
253
|
+
type WebhookEventType = 'user.created' | 'prediction.placed' | 'prediction.settled' | 'prediction.voided' | 'market.closed' | 'market.settled' | 'deposit.confirmed' | 'withdrawal.completed' | 'withdrawal.failed' | 'lottery.pool.drawn' | 'lottery.ticket.won';
|
|
254
|
+
interface WebhookEvent<T = unknown> {
|
|
156
255
|
event: WebhookEventType;
|
|
157
256
|
timestamp: string;
|
|
158
257
|
data: T;
|
|
159
258
|
}
|
|
160
|
-
interface
|
|
259
|
+
interface UserCreatedData {
|
|
260
|
+
puul_user_id: string;
|
|
261
|
+
external_user_id: string;
|
|
262
|
+
email: string;
|
|
263
|
+
phone: string;
|
|
264
|
+
country_code: string;
|
|
265
|
+
created_at: string;
|
|
266
|
+
}
|
|
267
|
+
interface PredictionPlacedData {
|
|
161
268
|
prediction_id: string;
|
|
269
|
+
user_id: string;
|
|
270
|
+
user_external_id: string;
|
|
162
271
|
market_id: string;
|
|
272
|
+
market_question: string;
|
|
163
273
|
outcome_id: string;
|
|
164
274
|
outcome_slug: string;
|
|
275
|
+
outcome_label: string;
|
|
276
|
+
stake_amount: number;
|
|
277
|
+
stake_currency: string;
|
|
278
|
+
estimated_return: string;
|
|
279
|
+
idempotency_key: string;
|
|
280
|
+
placed_at: string;
|
|
281
|
+
}
|
|
282
|
+
interface PredictionSettledData {
|
|
283
|
+
prediction_id: string;
|
|
284
|
+
user_id: string;
|
|
165
285
|
user_external_id: string;
|
|
166
|
-
|
|
286
|
+
market_id: string;
|
|
287
|
+
market_question: string;
|
|
288
|
+
outcome_id: string;
|
|
289
|
+
outcome_slug: string;
|
|
290
|
+
outcome_label: string;
|
|
291
|
+
stake_amount: string;
|
|
292
|
+
stake_currency: string;
|
|
293
|
+
status: 'WON' | 'LOST';
|
|
294
|
+
payout: string;
|
|
295
|
+
multiplier: string;
|
|
296
|
+
settled_at: string;
|
|
297
|
+
}
|
|
298
|
+
interface PredictionVoidedData {
|
|
299
|
+
prediction_id: string;
|
|
300
|
+
user_id: string;
|
|
301
|
+
user_external_id: string | null;
|
|
302
|
+
market_id: string;
|
|
303
|
+
market_question: string | null;
|
|
304
|
+
outcome_label: string | null;
|
|
167
305
|
stake_amount: string;
|
|
168
306
|
stake_currency: string;
|
|
169
|
-
|
|
307
|
+
refund_amount: string;
|
|
308
|
+
voided_at: string;
|
|
309
|
+
reason: string;
|
|
310
|
+
}
|
|
311
|
+
interface MarketClosedData {
|
|
312
|
+
market_id: string;
|
|
313
|
+
market_question: string;
|
|
314
|
+
market_type: string;
|
|
315
|
+
close_time: string;
|
|
316
|
+
closed_at: string;
|
|
317
|
+
currency: string;
|
|
318
|
+
volume: number;
|
|
319
|
+
prediction_count: number;
|
|
320
|
+
}
|
|
321
|
+
interface MarketSettledData {
|
|
322
|
+
market_id: string;
|
|
323
|
+
market_question: string;
|
|
324
|
+
market_type: string;
|
|
325
|
+
winning_outcome_id: string;
|
|
326
|
+
winning_outcome_slug: string | null;
|
|
327
|
+
winning_outcome_label: string | null;
|
|
328
|
+
currency: string;
|
|
329
|
+
total_pool: number;
|
|
330
|
+
winners_count: number;
|
|
331
|
+
total_payout: number;
|
|
170
332
|
settled_at: string;
|
|
171
333
|
}
|
|
334
|
+
interface DepositConfirmedData {
|
|
335
|
+
deposit_id: string;
|
|
336
|
+
user_id: string;
|
|
337
|
+
external_user_id: string;
|
|
338
|
+
amount: number;
|
|
339
|
+
currency: string;
|
|
340
|
+
amount_usd: number;
|
|
341
|
+
tx_hash: string;
|
|
342
|
+
status: string;
|
|
343
|
+
confirmed_at: string;
|
|
344
|
+
}
|
|
345
|
+
interface WithdrawalCompletedData {
|
|
346
|
+
withdrawal_id: string;
|
|
347
|
+
partner_id: string;
|
|
348
|
+
external_user_id: string;
|
|
349
|
+
amount: number;
|
|
350
|
+
currency: string;
|
|
351
|
+
method: string;
|
|
352
|
+
payout_reference: string | null;
|
|
353
|
+
completed_at: string;
|
|
354
|
+
}
|
|
355
|
+
interface WithdrawalFailedData {
|
|
356
|
+
withdrawal_id: string;
|
|
357
|
+
partner_id: string;
|
|
358
|
+
external_user_id: string;
|
|
359
|
+
amount: number;
|
|
360
|
+
currency: string;
|
|
361
|
+
method: string;
|
|
362
|
+
reason: string;
|
|
363
|
+
failed_at: string;
|
|
364
|
+
}
|
|
365
|
+
interface LotteryPoolDrawnData {
|
|
366
|
+
pool_id: string;
|
|
367
|
+
pool_title: string;
|
|
368
|
+
drawn_at: string;
|
|
369
|
+
winning_numbers: number[];
|
|
370
|
+
total_pool_amount: number;
|
|
371
|
+
total_entries: number;
|
|
372
|
+
takeout_amount: number;
|
|
373
|
+
total_payout: number;
|
|
374
|
+
your_entries: number;
|
|
375
|
+
your_winners: number;
|
|
376
|
+
your_total_winnings: number;
|
|
377
|
+
}
|
|
378
|
+
interface LotteryTicketWonData {
|
|
379
|
+
entry_id: string;
|
|
380
|
+
pool_id: string;
|
|
381
|
+
pool_title: string;
|
|
382
|
+
user_id: string;
|
|
383
|
+
user_external_id: string | null;
|
|
384
|
+
ticket_number: number;
|
|
385
|
+
prize_amount: number;
|
|
386
|
+
prize_tier: number;
|
|
387
|
+
drawn_at: string;
|
|
388
|
+
}
|
|
172
389
|
interface PuulApiError {
|
|
173
390
|
statusCode: number;
|
|
174
391
|
message: string | string[];
|
|
@@ -220,6 +437,7 @@ declare class PuulPartner {
|
|
|
220
437
|
readonly markets: MarketsAPI;
|
|
221
438
|
readonly predictions: PredictionsAPI;
|
|
222
439
|
readonly wallet: WalletAPI;
|
|
440
|
+
readonly lottery: LotteryAPI;
|
|
223
441
|
constructor(config: PuulPartnerConfig);
|
|
224
442
|
/** Get a valid access token, refreshing if needed */
|
|
225
443
|
getAccessToken(): Promise<string>;
|
|
@@ -274,6 +492,55 @@ declare class WalletAPI {
|
|
|
274
492
|
deposit(params: DepositParams): Promise<unknown>;
|
|
275
493
|
/** Get withdrawal fee estimate */
|
|
276
494
|
getWithdrawalFees(currency: string, amount: number): Promise<unknown>;
|
|
495
|
+
/**
|
|
496
|
+
* Withdraw from omnibus balance.
|
|
497
|
+
* Initiates a payout to the partner's configured bank account or crypto wallet.
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```typescript
|
|
501
|
+
* const result = await puul.wallet.withdraw({
|
|
502
|
+
* amount: 500000, // $5,000 in cents
|
|
503
|
+
* currency: 'USDC',
|
|
504
|
+
* method: 'bank', // or 'crypto'
|
|
505
|
+
* });
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
withdraw(params: WithdrawParams): Promise<WithdrawResult>;
|
|
509
|
+
}
|
|
510
|
+
declare class LotteryAPI {
|
|
511
|
+
private readonly client;
|
|
512
|
+
constructor(client: PuulPartner);
|
|
513
|
+
/** List lottery pools, optionally filtered by status and frequency */
|
|
514
|
+
listPools(options?: {
|
|
515
|
+
status?: LotteryPoolStatus;
|
|
516
|
+
frequency?: string;
|
|
517
|
+
limit?: number;
|
|
518
|
+
}): Promise<LotteryPool[]>;
|
|
519
|
+
/** Get a specific pool by ID */
|
|
520
|
+
getPool(poolId: string): Promise<LotteryPool>;
|
|
521
|
+
/**
|
|
522
|
+
* Buy ticket(s) for a linked user.
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```typescript
|
|
526
|
+
* const result = await puul.lottery.buyTicket('pool-uuid', {
|
|
527
|
+
* userId: 'puul-user-uuid',
|
|
528
|
+
* idempotencyKey: 'lottery-user456-pool1-001',
|
|
529
|
+
* quantity: 3,
|
|
530
|
+
* });
|
|
531
|
+
* ```
|
|
532
|
+
*/
|
|
533
|
+
buyTicket(poolId: string, params: BuyTicketParams): Promise<BuyTicketResponse>;
|
|
534
|
+
/** List lottery entries for your partner account */
|
|
535
|
+
listEntries(options?: {
|
|
536
|
+
poolId?: string;
|
|
537
|
+
status?: LotteryEntryStatus;
|
|
538
|
+
limit?: number;
|
|
539
|
+
}): Promise<LotteryEntriesResponse>;
|
|
540
|
+
/** Get a single lottery entry by ID */
|
|
541
|
+
getEntry(entryId: string): Promise<LotteryEntry>;
|
|
542
|
+
/** Get draw results for a completed pool */
|
|
543
|
+
getDrawResults(poolId: string): Promise<LotteryDrawResult>;
|
|
277
544
|
}
|
|
278
545
|
|
|
279
546
|
/**
|
|
@@ -318,22 +585,51 @@ declare function verifyWebhookSignature(payload: string, signature: string, secr
|
|
|
318
585
|
* const event = parseWebhookEvent(req.body);
|
|
319
586
|
*
|
|
320
587
|
* if (event.event === 'prediction.settled') {
|
|
321
|
-
* const { prediction_id, status,
|
|
588
|
+
* const { prediction_id, status, payout } = event.data;
|
|
322
589
|
* // Handle settlement...
|
|
323
590
|
* }
|
|
324
591
|
* ```
|
|
325
592
|
*/
|
|
326
593
|
declare function parseWebhookEvent(body: unknown): WebhookEvent;
|
|
327
|
-
/**
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
*/
|
|
332
|
-
declare function
|
|
594
|
+
/** Type guard for prediction.placed events. */
|
|
595
|
+
declare function isPredictionPlacedEvent(event: WebhookEvent): event is WebhookEvent<PredictionPlacedData>;
|
|
596
|
+
/** Type guard for prediction.settled events. */
|
|
597
|
+
declare function isPredictionSettledEvent(event: WebhookEvent): event is WebhookEvent<PredictionSettledData>;
|
|
598
|
+
/** Type guard for prediction.voided events. */
|
|
599
|
+
declare function isPredictionVoidedEvent(event: WebhookEvent): event is WebhookEvent<PredictionVoidedData>;
|
|
600
|
+
/** Type guard for market.closed events. */
|
|
601
|
+
declare function isMarketClosedEvent(event: WebhookEvent): event is WebhookEvent<MarketClosedData>;
|
|
602
|
+
/** Type guard for market.settled events. */
|
|
603
|
+
declare function isMarketSettledEvent(event: WebhookEvent): event is WebhookEvent<MarketSettledData>;
|
|
604
|
+
/** Type guard for deposit.confirmed events. */
|
|
605
|
+
declare function isDepositConfirmedEvent(event: WebhookEvent): event is WebhookEvent<DepositConfirmedData>;
|
|
606
|
+
/** Type guard for withdrawal.completed events. */
|
|
607
|
+
declare function isWithdrawalCompletedEvent(event: WebhookEvent): event is WebhookEvent<WithdrawalCompletedData>;
|
|
608
|
+
/** Type guard for withdrawal.failed events. */
|
|
609
|
+
declare function isWithdrawalFailedEvent(event: WebhookEvent): event is WebhookEvent<WithdrawalFailedData>;
|
|
610
|
+
/** Type guard for lottery.pool.drawn events. */
|
|
611
|
+
declare function isLotteryPoolDrawnEvent(event: WebhookEvent): event is WebhookEvent<LotteryPoolDrawnData>;
|
|
612
|
+
/** Type guard for lottery.ticket.won events. */
|
|
613
|
+
declare function isLotteryTicketWonEvent(event: WebhookEvent): event is WebhookEvent<LotteryTicketWonData>;
|
|
333
614
|
/**
|
|
334
615
|
* Convenience cast for prediction.settled event data.
|
|
335
616
|
* Call after verifying with `isPredictionSettledEvent`.
|
|
336
617
|
*/
|
|
337
618
|
declare function asPredictionSettledData(event: WebhookEvent): PredictionSettledData;
|
|
619
|
+
/**
|
|
620
|
+
* Convenience cast for market.settled event data.
|
|
621
|
+
* Call after verifying with `isMarketSettledEvent`.
|
|
622
|
+
*/
|
|
623
|
+
declare function asMarketSettledData(event: WebhookEvent): MarketSettledData;
|
|
624
|
+
/**
|
|
625
|
+
* Convenience cast for lottery.pool.drawn event data.
|
|
626
|
+
* Call after verifying with `isLotteryPoolDrawnEvent`.
|
|
627
|
+
*/
|
|
628
|
+
declare function asLotteryPoolDrawnData(event: WebhookEvent): LotteryPoolDrawnData;
|
|
629
|
+
/**
|
|
630
|
+
* Convenience cast for lottery.ticket.won event data.
|
|
631
|
+
* Call after verifying with `isLotteryTicketWonEvent`.
|
|
632
|
+
*/
|
|
633
|
+
declare function asLotteryTicketWonData(event: WebhookEvent): LotteryTicketWonData;
|
|
338
634
|
|
|
339
|
-
export { type AccessTokenResponse, type CreateLinkTokenParams, type CreatePendingPredictionParams, type CreateQuoteParams, type Currency, type DepositAccountInfo, type DepositParams, type LinkTokenResponse, type Market, type MarketOutcome, type PendingPrediction, type PlacePredictionParams, type Prediction, type PredictionListResponse, type PredictionSettledData, type PredictionStatus, type PuulApiError, PuulError, PuulPartner, type PuulPartnerConfig, type QuoteResponse, type SessionResponse, type WalletBalance, type WebhookEvent, type WebhookEventType, asPredictionSettledData, isPredictionSettledEvent, parseWebhookEvent, verifyWebhookSignature };
|
|
635
|
+
export { type AccessTokenResponse, type BuyTicketParams, type BuyTicketResponse, type CreateLinkTokenParams, type CreatePendingPredictionParams, type CreateQuoteParams, type Currency, type DepositAccountInfo, type DepositConfirmedData, type DepositParams, type LinkTokenResponse, type LotteryDrawResult, type LotteryEntriesResponse, type LotteryEntry, type LotteryEntryStatus, type LotteryPool, type LotteryPoolDrawnData, type LotteryPoolFrequency, type LotteryPoolStatus, type LotteryPoolType, type LotteryTicketWonData, type Market, type MarketClosedData, type MarketOutcome, type MarketSettledData, type PendingPrediction, type PlacePredictionParams, type Prediction, type PredictionListResponse, type PredictionPlacedData, type PredictionSettledData, type PredictionStatus, type PredictionVoidedData, type PrizeTier, type PuulApiError, PuulError, PuulPartner, type PuulPartnerConfig, type QuoteResponse, type SessionResponse, type UserCreatedData, type WalletBalance, type WebhookEvent, type WebhookEventType, type WithdrawMethod, type WithdrawParams, type WithdrawResult, type WithdrawalCompletedData, type WithdrawalFailedData, asLotteryPoolDrawnData, asLotteryTicketWonData, asMarketSettledData, asPredictionSettledData, isDepositConfirmedEvent, isLotteryPoolDrawnEvent, isLotteryTicketWonEvent, isMarketClosedEvent, isMarketSettledEvent, isPredictionPlacedEvent, isPredictionSettledEvent, isPredictionVoidedEvent, isWithdrawalCompletedEvent, isWithdrawalFailedEvent, parseWebhookEvent, verifyWebhookSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -33,22 +33,27 @@ interface MarketOutcome {
|
|
|
33
33
|
id: string;
|
|
34
34
|
slug: string;
|
|
35
35
|
label: string;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
display_order: number;
|
|
37
|
+
pool_amount: string;
|
|
38
|
+
predictor_count: number;
|
|
39
|
+
prediction_count: number;
|
|
40
40
|
}
|
|
41
41
|
interface Market {
|
|
42
42
|
id: string;
|
|
43
43
|
question: string;
|
|
44
|
-
description: string;
|
|
45
44
|
category: string;
|
|
45
|
+
image_url: string;
|
|
46
|
+
market_type: string;
|
|
46
47
|
status: string;
|
|
47
48
|
currency: string;
|
|
48
49
|
close_time: string;
|
|
49
50
|
freeze_at: string | null;
|
|
50
|
-
target_countries: string[];
|
|
51
51
|
outcomes: MarketOutcome[];
|
|
52
|
+
volume: number;
|
|
53
|
+
volume_currency: string;
|
|
54
|
+
predictor_count: number;
|
|
55
|
+
prediction_count: number;
|
|
56
|
+
created_at: string;
|
|
52
57
|
}
|
|
53
58
|
type PredictionStatus = 'OPEN' | 'WON' | 'LOST' | 'VOIDED';
|
|
54
59
|
type Currency = 'NGN' | 'USDC' | 'USDT' | 'KES' | 'GHS' | 'ZAR';
|
|
@@ -149,26 +154,238 @@ interface DepositParams {
|
|
|
149
154
|
idempotency_key: string;
|
|
150
155
|
reference?: string;
|
|
151
156
|
}
|
|
152
|
-
type
|
|
153
|
-
interface
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
type WithdrawMethod = 'bank' | 'crypto';
|
|
158
|
+
interface WithdrawParams {
|
|
159
|
+
/** Amount to withdraw in minor units (cents) */
|
|
160
|
+
amount: number;
|
|
161
|
+
/** Currency to withdraw. Defaults to USDC */
|
|
162
|
+
currency?: Currency;
|
|
163
|
+
/** Payout method: 'bank' for fiat, 'crypto' for on-chain */
|
|
164
|
+
method?: WithdrawMethod;
|
|
165
|
+
}
|
|
166
|
+
interface WithdrawResult {
|
|
167
|
+
withdrawalId: string;
|
|
168
|
+
partnerId: string;
|
|
169
|
+
amount: number;
|
|
170
|
+
currency: string;
|
|
171
|
+
method: WithdrawMethod;
|
|
172
|
+
payoutReference: string | null;
|
|
173
|
+
status: string;
|
|
174
|
+
}
|
|
175
|
+
type LotteryPoolType = 'winner_takes_all' | 'tiered';
|
|
176
|
+
type LotteryPoolFrequency = 'daily' | 'weekly' | 'monthly' | 'quarterly';
|
|
177
|
+
type LotteryPoolStatus = 'upcoming' | 'open' | 'drawing' | 'settled' | 'cancelled';
|
|
178
|
+
type LotteryEntryStatus = 'active' | 'won' | 'lost' | 'refunded';
|
|
179
|
+
interface PrizeTier {
|
|
180
|
+
/** 1-based rank (1 = first place) */
|
|
181
|
+
rank: number;
|
|
182
|
+
/** Percentage of distributable pool in basis points (5000 = 50%) */
|
|
183
|
+
pct: number;
|
|
184
|
+
}
|
|
185
|
+
interface LotteryPool {
|
|
186
|
+
id: string;
|
|
187
|
+
title: string;
|
|
188
|
+
description: string | null;
|
|
189
|
+
type: LotteryPoolType;
|
|
190
|
+
frequency: LotteryPoolFrequency;
|
|
191
|
+
status: LotteryPoolStatus;
|
|
192
|
+
ticket_price: string;
|
|
193
|
+
currency: string;
|
|
194
|
+
max_tickets: number | null;
|
|
195
|
+
max_tickets_per_user: number | null;
|
|
196
|
+
total_entries: number;
|
|
197
|
+
total_pool_amount: string;
|
|
198
|
+
opens_at: string;
|
|
199
|
+
draws_at: string;
|
|
200
|
+
drawn_at: string | null;
|
|
201
|
+
winning_numbers: number[];
|
|
202
|
+
prize_tiers: PrizeTier[];
|
|
203
|
+
takeout_rate_bps: number;
|
|
204
|
+
}
|
|
205
|
+
interface LotteryEntry {
|
|
206
|
+
id: string;
|
|
207
|
+
pool_id: string;
|
|
208
|
+
user_id: string | null;
|
|
209
|
+
user_external_id: string | null;
|
|
210
|
+
ticket_number: number;
|
|
211
|
+
amount_paid: string;
|
|
212
|
+
currency: string;
|
|
213
|
+
status: LotteryEntryStatus;
|
|
214
|
+
prize_amount: string | null;
|
|
215
|
+
prize_tier: number | null;
|
|
216
|
+
purchased_at: string;
|
|
217
|
+
}
|
|
218
|
+
interface LotteryEntriesResponse {
|
|
219
|
+
entries: LotteryEntry[];
|
|
220
|
+
total: number;
|
|
221
|
+
}
|
|
222
|
+
interface BuyTicketParams {
|
|
223
|
+
/** Puul user ID of the linked user */
|
|
224
|
+
userId: string;
|
|
225
|
+
/** Unique key to prevent duplicate purchases */
|
|
226
|
+
idempotencyKey: string;
|
|
227
|
+
/** Number of tickets (default: 1) */
|
|
228
|
+
quantity?: number;
|
|
229
|
+
/** Your external user ID (for tracking) */
|
|
230
|
+
userExternalId?: string;
|
|
231
|
+
}
|
|
232
|
+
interface BuyTicketResponse {
|
|
233
|
+
entries: LotteryEntry[];
|
|
234
|
+
}
|
|
235
|
+
interface LotteryDrawResult {
|
|
236
|
+
pool_id: string;
|
|
237
|
+
status: string;
|
|
238
|
+
drawn_at: string | null;
|
|
239
|
+
winning_numbers: number[];
|
|
240
|
+
total_pool_amount: string;
|
|
241
|
+
your_entries: Array<{
|
|
242
|
+
id: string;
|
|
243
|
+
ticket_number: number;
|
|
244
|
+
user_id: string | null;
|
|
245
|
+
user_external_id: string | null;
|
|
246
|
+
status: string;
|
|
247
|
+
prize_amount: string | null;
|
|
248
|
+
prize_tier: number | null;
|
|
249
|
+
}>;
|
|
250
|
+
your_winners: number;
|
|
251
|
+
your_total_winnings: number;
|
|
252
|
+
}
|
|
253
|
+
type WebhookEventType = 'user.created' | 'prediction.placed' | 'prediction.settled' | 'prediction.voided' | 'market.closed' | 'market.settled' | 'deposit.confirmed' | 'withdrawal.completed' | 'withdrawal.failed' | 'lottery.pool.drawn' | 'lottery.ticket.won';
|
|
254
|
+
interface WebhookEvent<T = unknown> {
|
|
156
255
|
event: WebhookEventType;
|
|
157
256
|
timestamp: string;
|
|
158
257
|
data: T;
|
|
159
258
|
}
|
|
160
|
-
interface
|
|
259
|
+
interface UserCreatedData {
|
|
260
|
+
puul_user_id: string;
|
|
261
|
+
external_user_id: string;
|
|
262
|
+
email: string;
|
|
263
|
+
phone: string;
|
|
264
|
+
country_code: string;
|
|
265
|
+
created_at: string;
|
|
266
|
+
}
|
|
267
|
+
interface PredictionPlacedData {
|
|
161
268
|
prediction_id: string;
|
|
269
|
+
user_id: string;
|
|
270
|
+
user_external_id: string;
|
|
162
271
|
market_id: string;
|
|
272
|
+
market_question: string;
|
|
163
273
|
outcome_id: string;
|
|
164
274
|
outcome_slug: string;
|
|
275
|
+
outcome_label: string;
|
|
276
|
+
stake_amount: number;
|
|
277
|
+
stake_currency: string;
|
|
278
|
+
estimated_return: string;
|
|
279
|
+
idempotency_key: string;
|
|
280
|
+
placed_at: string;
|
|
281
|
+
}
|
|
282
|
+
interface PredictionSettledData {
|
|
283
|
+
prediction_id: string;
|
|
284
|
+
user_id: string;
|
|
165
285
|
user_external_id: string;
|
|
166
|
-
|
|
286
|
+
market_id: string;
|
|
287
|
+
market_question: string;
|
|
288
|
+
outcome_id: string;
|
|
289
|
+
outcome_slug: string;
|
|
290
|
+
outcome_label: string;
|
|
291
|
+
stake_amount: string;
|
|
292
|
+
stake_currency: string;
|
|
293
|
+
status: 'WON' | 'LOST';
|
|
294
|
+
payout: string;
|
|
295
|
+
multiplier: string;
|
|
296
|
+
settled_at: string;
|
|
297
|
+
}
|
|
298
|
+
interface PredictionVoidedData {
|
|
299
|
+
prediction_id: string;
|
|
300
|
+
user_id: string;
|
|
301
|
+
user_external_id: string | null;
|
|
302
|
+
market_id: string;
|
|
303
|
+
market_question: string | null;
|
|
304
|
+
outcome_label: string | null;
|
|
167
305
|
stake_amount: string;
|
|
168
306
|
stake_currency: string;
|
|
169
|
-
|
|
307
|
+
refund_amount: string;
|
|
308
|
+
voided_at: string;
|
|
309
|
+
reason: string;
|
|
310
|
+
}
|
|
311
|
+
interface MarketClosedData {
|
|
312
|
+
market_id: string;
|
|
313
|
+
market_question: string;
|
|
314
|
+
market_type: string;
|
|
315
|
+
close_time: string;
|
|
316
|
+
closed_at: string;
|
|
317
|
+
currency: string;
|
|
318
|
+
volume: number;
|
|
319
|
+
prediction_count: number;
|
|
320
|
+
}
|
|
321
|
+
interface MarketSettledData {
|
|
322
|
+
market_id: string;
|
|
323
|
+
market_question: string;
|
|
324
|
+
market_type: string;
|
|
325
|
+
winning_outcome_id: string;
|
|
326
|
+
winning_outcome_slug: string | null;
|
|
327
|
+
winning_outcome_label: string | null;
|
|
328
|
+
currency: string;
|
|
329
|
+
total_pool: number;
|
|
330
|
+
winners_count: number;
|
|
331
|
+
total_payout: number;
|
|
170
332
|
settled_at: string;
|
|
171
333
|
}
|
|
334
|
+
interface DepositConfirmedData {
|
|
335
|
+
deposit_id: string;
|
|
336
|
+
user_id: string;
|
|
337
|
+
external_user_id: string;
|
|
338
|
+
amount: number;
|
|
339
|
+
currency: string;
|
|
340
|
+
amount_usd: number;
|
|
341
|
+
tx_hash: string;
|
|
342
|
+
status: string;
|
|
343
|
+
confirmed_at: string;
|
|
344
|
+
}
|
|
345
|
+
interface WithdrawalCompletedData {
|
|
346
|
+
withdrawal_id: string;
|
|
347
|
+
partner_id: string;
|
|
348
|
+
external_user_id: string;
|
|
349
|
+
amount: number;
|
|
350
|
+
currency: string;
|
|
351
|
+
method: string;
|
|
352
|
+
payout_reference: string | null;
|
|
353
|
+
completed_at: string;
|
|
354
|
+
}
|
|
355
|
+
interface WithdrawalFailedData {
|
|
356
|
+
withdrawal_id: string;
|
|
357
|
+
partner_id: string;
|
|
358
|
+
external_user_id: string;
|
|
359
|
+
amount: number;
|
|
360
|
+
currency: string;
|
|
361
|
+
method: string;
|
|
362
|
+
reason: string;
|
|
363
|
+
failed_at: string;
|
|
364
|
+
}
|
|
365
|
+
interface LotteryPoolDrawnData {
|
|
366
|
+
pool_id: string;
|
|
367
|
+
pool_title: string;
|
|
368
|
+
drawn_at: string;
|
|
369
|
+
winning_numbers: number[];
|
|
370
|
+
total_pool_amount: number;
|
|
371
|
+
total_entries: number;
|
|
372
|
+
takeout_amount: number;
|
|
373
|
+
total_payout: number;
|
|
374
|
+
your_entries: number;
|
|
375
|
+
your_winners: number;
|
|
376
|
+
your_total_winnings: number;
|
|
377
|
+
}
|
|
378
|
+
interface LotteryTicketWonData {
|
|
379
|
+
entry_id: string;
|
|
380
|
+
pool_id: string;
|
|
381
|
+
pool_title: string;
|
|
382
|
+
user_id: string;
|
|
383
|
+
user_external_id: string | null;
|
|
384
|
+
ticket_number: number;
|
|
385
|
+
prize_amount: number;
|
|
386
|
+
prize_tier: number;
|
|
387
|
+
drawn_at: string;
|
|
388
|
+
}
|
|
172
389
|
interface PuulApiError {
|
|
173
390
|
statusCode: number;
|
|
174
391
|
message: string | string[];
|
|
@@ -220,6 +437,7 @@ declare class PuulPartner {
|
|
|
220
437
|
readonly markets: MarketsAPI;
|
|
221
438
|
readonly predictions: PredictionsAPI;
|
|
222
439
|
readonly wallet: WalletAPI;
|
|
440
|
+
readonly lottery: LotteryAPI;
|
|
223
441
|
constructor(config: PuulPartnerConfig);
|
|
224
442
|
/** Get a valid access token, refreshing if needed */
|
|
225
443
|
getAccessToken(): Promise<string>;
|
|
@@ -274,6 +492,55 @@ declare class WalletAPI {
|
|
|
274
492
|
deposit(params: DepositParams): Promise<unknown>;
|
|
275
493
|
/** Get withdrawal fee estimate */
|
|
276
494
|
getWithdrawalFees(currency: string, amount: number): Promise<unknown>;
|
|
495
|
+
/**
|
|
496
|
+
* Withdraw from omnibus balance.
|
|
497
|
+
* Initiates a payout to the partner's configured bank account or crypto wallet.
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```typescript
|
|
501
|
+
* const result = await puul.wallet.withdraw({
|
|
502
|
+
* amount: 500000, // $5,000 in cents
|
|
503
|
+
* currency: 'USDC',
|
|
504
|
+
* method: 'bank', // or 'crypto'
|
|
505
|
+
* });
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
withdraw(params: WithdrawParams): Promise<WithdrawResult>;
|
|
509
|
+
}
|
|
510
|
+
declare class LotteryAPI {
|
|
511
|
+
private readonly client;
|
|
512
|
+
constructor(client: PuulPartner);
|
|
513
|
+
/** List lottery pools, optionally filtered by status and frequency */
|
|
514
|
+
listPools(options?: {
|
|
515
|
+
status?: LotteryPoolStatus;
|
|
516
|
+
frequency?: string;
|
|
517
|
+
limit?: number;
|
|
518
|
+
}): Promise<LotteryPool[]>;
|
|
519
|
+
/** Get a specific pool by ID */
|
|
520
|
+
getPool(poolId: string): Promise<LotteryPool>;
|
|
521
|
+
/**
|
|
522
|
+
* Buy ticket(s) for a linked user.
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```typescript
|
|
526
|
+
* const result = await puul.lottery.buyTicket('pool-uuid', {
|
|
527
|
+
* userId: 'puul-user-uuid',
|
|
528
|
+
* idempotencyKey: 'lottery-user456-pool1-001',
|
|
529
|
+
* quantity: 3,
|
|
530
|
+
* });
|
|
531
|
+
* ```
|
|
532
|
+
*/
|
|
533
|
+
buyTicket(poolId: string, params: BuyTicketParams): Promise<BuyTicketResponse>;
|
|
534
|
+
/** List lottery entries for your partner account */
|
|
535
|
+
listEntries(options?: {
|
|
536
|
+
poolId?: string;
|
|
537
|
+
status?: LotteryEntryStatus;
|
|
538
|
+
limit?: number;
|
|
539
|
+
}): Promise<LotteryEntriesResponse>;
|
|
540
|
+
/** Get a single lottery entry by ID */
|
|
541
|
+
getEntry(entryId: string): Promise<LotteryEntry>;
|
|
542
|
+
/** Get draw results for a completed pool */
|
|
543
|
+
getDrawResults(poolId: string): Promise<LotteryDrawResult>;
|
|
277
544
|
}
|
|
278
545
|
|
|
279
546
|
/**
|
|
@@ -318,22 +585,51 @@ declare function verifyWebhookSignature(payload: string, signature: string, secr
|
|
|
318
585
|
* const event = parseWebhookEvent(req.body);
|
|
319
586
|
*
|
|
320
587
|
* if (event.event === 'prediction.settled') {
|
|
321
|
-
* const { prediction_id, status,
|
|
588
|
+
* const { prediction_id, status, payout } = event.data;
|
|
322
589
|
* // Handle settlement...
|
|
323
590
|
* }
|
|
324
591
|
* ```
|
|
325
592
|
*/
|
|
326
593
|
declare function parseWebhookEvent(body: unknown): WebhookEvent;
|
|
327
|
-
/**
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
*/
|
|
332
|
-
declare function
|
|
594
|
+
/** Type guard for prediction.placed events. */
|
|
595
|
+
declare function isPredictionPlacedEvent(event: WebhookEvent): event is WebhookEvent<PredictionPlacedData>;
|
|
596
|
+
/** Type guard for prediction.settled events. */
|
|
597
|
+
declare function isPredictionSettledEvent(event: WebhookEvent): event is WebhookEvent<PredictionSettledData>;
|
|
598
|
+
/** Type guard for prediction.voided events. */
|
|
599
|
+
declare function isPredictionVoidedEvent(event: WebhookEvent): event is WebhookEvent<PredictionVoidedData>;
|
|
600
|
+
/** Type guard for market.closed events. */
|
|
601
|
+
declare function isMarketClosedEvent(event: WebhookEvent): event is WebhookEvent<MarketClosedData>;
|
|
602
|
+
/** Type guard for market.settled events. */
|
|
603
|
+
declare function isMarketSettledEvent(event: WebhookEvent): event is WebhookEvent<MarketSettledData>;
|
|
604
|
+
/** Type guard for deposit.confirmed events. */
|
|
605
|
+
declare function isDepositConfirmedEvent(event: WebhookEvent): event is WebhookEvent<DepositConfirmedData>;
|
|
606
|
+
/** Type guard for withdrawal.completed events. */
|
|
607
|
+
declare function isWithdrawalCompletedEvent(event: WebhookEvent): event is WebhookEvent<WithdrawalCompletedData>;
|
|
608
|
+
/** Type guard for withdrawal.failed events. */
|
|
609
|
+
declare function isWithdrawalFailedEvent(event: WebhookEvent): event is WebhookEvent<WithdrawalFailedData>;
|
|
610
|
+
/** Type guard for lottery.pool.drawn events. */
|
|
611
|
+
declare function isLotteryPoolDrawnEvent(event: WebhookEvent): event is WebhookEvent<LotteryPoolDrawnData>;
|
|
612
|
+
/** Type guard for lottery.ticket.won events. */
|
|
613
|
+
declare function isLotteryTicketWonEvent(event: WebhookEvent): event is WebhookEvent<LotteryTicketWonData>;
|
|
333
614
|
/**
|
|
334
615
|
* Convenience cast for prediction.settled event data.
|
|
335
616
|
* Call after verifying with `isPredictionSettledEvent`.
|
|
336
617
|
*/
|
|
337
618
|
declare function asPredictionSettledData(event: WebhookEvent): PredictionSettledData;
|
|
619
|
+
/**
|
|
620
|
+
* Convenience cast for market.settled event data.
|
|
621
|
+
* Call after verifying with `isMarketSettledEvent`.
|
|
622
|
+
*/
|
|
623
|
+
declare function asMarketSettledData(event: WebhookEvent): MarketSettledData;
|
|
624
|
+
/**
|
|
625
|
+
* Convenience cast for lottery.pool.drawn event data.
|
|
626
|
+
* Call after verifying with `isLotteryPoolDrawnEvent`.
|
|
627
|
+
*/
|
|
628
|
+
declare function asLotteryPoolDrawnData(event: WebhookEvent): LotteryPoolDrawnData;
|
|
629
|
+
/**
|
|
630
|
+
* Convenience cast for lottery.ticket.won event data.
|
|
631
|
+
* Call after verifying with `isLotteryTicketWonEvent`.
|
|
632
|
+
*/
|
|
633
|
+
declare function asLotteryTicketWonData(event: WebhookEvent): LotteryTicketWonData;
|
|
338
634
|
|
|
339
|
-
export { type AccessTokenResponse, type CreateLinkTokenParams, type CreatePendingPredictionParams, type CreateQuoteParams, type Currency, type DepositAccountInfo, type DepositParams, type LinkTokenResponse, type Market, type MarketOutcome, type PendingPrediction, type PlacePredictionParams, type Prediction, type PredictionListResponse, type PredictionSettledData, type PredictionStatus, type PuulApiError, PuulError, PuulPartner, type PuulPartnerConfig, type QuoteResponse, type SessionResponse, type WalletBalance, type WebhookEvent, type WebhookEventType, asPredictionSettledData, isPredictionSettledEvent, parseWebhookEvent, verifyWebhookSignature };
|
|
635
|
+
export { type AccessTokenResponse, type BuyTicketParams, type BuyTicketResponse, type CreateLinkTokenParams, type CreatePendingPredictionParams, type CreateQuoteParams, type Currency, type DepositAccountInfo, type DepositConfirmedData, type DepositParams, type LinkTokenResponse, type LotteryDrawResult, type LotteryEntriesResponse, type LotteryEntry, type LotteryEntryStatus, type LotteryPool, type LotteryPoolDrawnData, type LotteryPoolFrequency, type LotteryPoolStatus, type LotteryPoolType, type LotteryTicketWonData, type Market, type MarketClosedData, type MarketOutcome, type MarketSettledData, type PendingPrediction, type PlacePredictionParams, type Prediction, type PredictionListResponse, type PredictionPlacedData, type PredictionSettledData, type PredictionStatus, type PredictionVoidedData, type PrizeTier, type PuulApiError, PuulError, PuulPartner, type PuulPartnerConfig, type QuoteResponse, type SessionResponse, type UserCreatedData, type WalletBalance, type WebhookEvent, type WebhookEventType, type WithdrawMethod, type WithdrawParams, type WithdrawResult, type WithdrawalCompletedData, type WithdrawalFailedData, asLotteryPoolDrawnData, asLotteryTicketWonData, asMarketSettledData, asPredictionSettledData, isDepositConfirmedEvent, isLotteryPoolDrawnEvent, isLotteryTicketWonEvent, isMarketClosedEvent, isMarketSettledEvent, isPredictionPlacedEvent, isPredictionSettledEvent, isPredictionVoidedEvent, isWithdrawalCompletedEvent, isWithdrawalFailedEvent, parseWebhookEvent, verifyWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -22,8 +22,20 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
PuulError: () => PuulError,
|
|
24
24
|
PuulPartner: () => PuulPartner,
|
|
25
|
+
asLotteryPoolDrawnData: () => asLotteryPoolDrawnData,
|
|
26
|
+
asLotteryTicketWonData: () => asLotteryTicketWonData,
|
|
27
|
+
asMarketSettledData: () => asMarketSettledData,
|
|
25
28
|
asPredictionSettledData: () => asPredictionSettledData,
|
|
29
|
+
isDepositConfirmedEvent: () => isDepositConfirmedEvent,
|
|
30
|
+
isLotteryPoolDrawnEvent: () => isLotteryPoolDrawnEvent,
|
|
31
|
+
isLotteryTicketWonEvent: () => isLotteryTicketWonEvent,
|
|
32
|
+
isMarketClosedEvent: () => isMarketClosedEvent,
|
|
33
|
+
isMarketSettledEvent: () => isMarketSettledEvent,
|
|
34
|
+
isPredictionPlacedEvent: () => isPredictionPlacedEvent,
|
|
26
35
|
isPredictionSettledEvent: () => isPredictionSettledEvent,
|
|
36
|
+
isPredictionVoidedEvent: () => isPredictionVoidedEvent,
|
|
37
|
+
isWithdrawalCompletedEvent: () => isWithdrawalCompletedEvent,
|
|
38
|
+
isWithdrawalFailedEvent: () => isWithdrawalFailedEvent,
|
|
27
39
|
parseWebhookEvent: () => parseWebhookEvent,
|
|
28
40
|
verifyWebhookSignature: () => verifyWebhookSignature
|
|
29
41
|
});
|
|
@@ -59,6 +71,7 @@ var PuulPartner = class {
|
|
|
59
71
|
this.markets = new MarketsAPI(this);
|
|
60
72
|
this.predictions = new PredictionsAPI(this);
|
|
61
73
|
this.wallet = new WalletAPI(this);
|
|
74
|
+
this.lottery = new LotteryAPI(this);
|
|
62
75
|
}
|
|
63
76
|
// ==========================================================
|
|
64
77
|
// Internal HTTP layer
|
|
@@ -229,22 +242,93 @@ var WalletAPI = class {
|
|
|
229
242
|
async getWithdrawalFees(currency, amount) {
|
|
230
243
|
return this.client.request("GET", `/partner/wallet/withdrawal-fees?currency=${currency}&amount=${amount}`);
|
|
231
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Withdraw from omnibus balance.
|
|
247
|
+
* Initiates a payout to the partner's configured bank account or crypto wallet.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* const result = await puul.wallet.withdraw({
|
|
252
|
+
* amount: 500000, // $5,000 in cents
|
|
253
|
+
* currency: 'USDC',
|
|
254
|
+
* method: 'bank', // or 'crypto'
|
|
255
|
+
* });
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
async withdraw(params) {
|
|
259
|
+
return this.client.request("POST", "/partner/wallet/withdraw", params);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var LotteryAPI = class {
|
|
263
|
+
constructor(client) {
|
|
264
|
+
this.client = client;
|
|
265
|
+
}
|
|
266
|
+
/** List lottery pools, optionally filtered by status and frequency */
|
|
267
|
+
async listPools(options) {
|
|
268
|
+
const params = new URLSearchParams();
|
|
269
|
+
if (options?.status) params.set("status", options.status);
|
|
270
|
+
if (options?.frequency) params.set("frequency", options.frequency);
|
|
271
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
272
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
273
|
+
return this.client.request("GET", `/partner/lottery/pools${query}`);
|
|
274
|
+
}
|
|
275
|
+
/** Get a specific pool by ID */
|
|
276
|
+
async getPool(poolId) {
|
|
277
|
+
return this.client.request("GET", `/partner/lottery/pools/${poolId}`);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Buy ticket(s) for a linked user.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* const result = await puul.lottery.buyTicket('pool-uuid', {
|
|
285
|
+
* userId: 'puul-user-uuid',
|
|
286
|
+
* idempotencyKey: 'lottery-user456-pool1-001',
|
|
287
|
+
* quantity: 3,
|
|
288
|
+
* });
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
async buyTicket(poolId, params) {
|
|
292
|
+
return this.client.request("POST", `/partner/lottery/pools/${poolId}/buy`, {
|
|
293
|
+
user_id: params.userId,
|
|
294
|
+
idempotency_key: params.idempotencyKey,
|
|
295
|
+
quantity: params.quantity,
|
|
296
|
+
user_external_id: params.userExternalId
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
/** List lottery entries for your partner account */
|
|
300
|
+
async listEntries(options) {
|
|
301
|
+
const params = new URLSearchParams();
|
|
302
|
+
if (options?.poolId) params.set("pool_id", options.poolId);
|
|
303
|
+
if (options?.status) params.set("status", options.status);
|
|
304
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
305
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
306
|
+
return this.client.request("GET", `/partner/lottery/entries${query}`);
|
|
307
|
+
}
|
|
308
|
+
/** Get a single lottery entry by ID */
|
|
309
|
+
async getEntry(entryId) {
|
|
310
|
+
return this.client.request("GET", `/partner/lottery/entries/${entryId}`);
|
|
311
|
+
}
|
|
312
|
+
/** Get draw results for a completed pool */
|
|
313
|
+
async getDrawResults(poolId) {
|
|
314
|
+
return this.client.request("GET", `/partner/lottery/pools/${poolId}/results`);
|
|
315
|
+
}
|
|
232
316
|
};
|
|
233
317
|
|
|
234
318
|
// src/webhooks.ts
|
|
235
|
-
var
|
|
319
|
+
var import_node_crypto = require("crypto");
|
|
236
320
|
function verifyWebhookSignature(payload, signature, secret) {
|
|
237
321
|
if (!payload || !signature || !secret) {
|
|
238
322
|
return false;
|
|
239
323
|
}
|
|
240
|
-
const expectedSignature = (0,
|
|
324
|
+
const expectedSignature = (0, import_node_crypto.createHmac)("sha256", secret).update(payload).digest("hex");
|
|
241
325
|
try {
|
|
242
326
|
const sigBuffer = Buffer.from(signature, "hex");
|
|
243
327
|
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
244
328
|
if (sigBuffer.length !== expectedBuffer.length) {
|
|
245
329
|
return false;
|
|
246
330
|
}
|
|
247
|
-
return (0,
|
|
331
|
+
return (0, import_node_crypto.timingSafeEqual)(sigBuffer, expectedBuffer);
|
|
248
332
|
} catch {
|
|
249
333
|
return false;
|
|
250
334
|
}
|
|
@@ -255,7 +339,7 @@ function parseWebhookEvent(body) {
|
|
|
255
339
|
}
|
|
256
340
|
const event = body;
|
|
257
341
|
if (typeof event.event !== "string") {
|
|
258
|
-
throw new
|
|
342
|
+
throw new TypeError('Invalid webhook body: missing "event" field');
|
|
259
343
|
}
|
|
260
344
|
return {
|
|
261
345
|
event: event.event,
|
|
@@ -263,18 +347,66 @@ function parseWebhookEvent(body) {
|
|
|
263
347
|
data: event.data || {}
|
|
264
348
|
};
|
|
265
349
|
}
|
|
350
|
+
function isPredictionPlacedEvent(event) {
|
|
351
|
+
return event.event === "prediction.placed";
|
|
352
|
+
}
|
|
266
353
|
function isPredictionSettledEvent(event) {
|
|
267
354
|
return event.event === "prediction.settled";
|
|
268
355
|
}
|
|
356
|
+
function isPredictionVoidedEvent(event) {
|
|
357
|
+
return event.event === "prediction.voided";
|
|
358
|
+
}
|
|
359
|
+
function isMarketClosedEvent(event) {
|
|
360
|
+
return event.event === "market.closed";
|
|
361
|
+
}
|
|
362
|
+
function isMarketSettledEvent(event) {
|
|
363
|
+
return event.event === "market.settled";
|
|
364
|
+
}
|
|
365
|
+
function isDepositConfirmedEvent(event) {
|
|
366
|
+
return event.event === "deposit.confirmed";
|
|
367
|
+
}
|
|
368
|
+
function isWithdrawalCompletedEvent(event) {
|
|
369
|
+
return event.event === "withdrawal.completed";
|
|
370
|
+
}
|
|
371
|
+
function isWithdrawalFailedEvent(event) {
|
|
372
|
+
return event.event === "withdrawal.failed";
|
|
373
|
+
}
|
|
374
|
+
function isLotteryPoolDrawnEvent(event) {
|
|
375
|
+
return event.event === "lottery.pool.drawn";
|
|
376
|
+
}
|
|
377
|
+
function isLotteryTicketWonEvent(event) {
|
|
378
|
+
return event.event === "lottery.ticket.won";
|
|
379
|
+
}
|
|
269
380
|
function asPredictionSettledData(event) {
|
|
270
381
|
return event.data;
|
|
271
382
|
}
|
|
383
|
+
function asMarketSettledData(event) {
|
|
384
|
+
return event.data;
|
|
385
|
+
}
|
|
386
|
+
function asLotteryPoolDrawnData(event) {
|
|
387
|
+
return event.data;
|
|
388
|
+
}
|
|
389
|
+
function asLotteryTicketWonData(event) {
|
|
390
|
+
return event.data;
|
|
391
|
+
}
|
|
272
392
|
// Annotate the CommonJS export names for ESM import in node:
|
|
273
393
|
0 && (module.exports = {
|
|
274
394
|
PuulError,
|
|
275
395
|
PuulPartner,
|
|
396
|
+
asLotteryPoolDrawnData,
|
|
397
|
+
asLotteryTicketWonData,
|
|
398
|
+
asMarketSettledData,
|
|
276
399
|
asPredictionSettledData,
|
|
400
|
+
isDepositConfirmedEvent,
|
|
401
|
+
isLotteryPoolDrawnEvent,
|
|
402
|
+
isLotteryTicketWonEvent,
|
|
403
|
+
isMarketClosedEvent,
|
|
404
|
+
isMarketSettledEvent,
|
|
405
|
+
isPredictionPlacedEvent,
|
|
277
406
|
isPredictionSettledEvent,
|
|
407
|
+
isPredictionVoidedEvent,
|
|
408
|
+
isWithdrawalCompletedEvent,
|
|
409
|
+
isWithdrawalFailedEvent,
|
|
278
410
|
parseWebhookEvent,
|
|
279
411
|
verifyWebhookSignature
|
|
280
412
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -28,6 +28,7 @@ var PuulPartner = class {
|
|
|
28
28
|
this.markets = new MarketsAPI(this);
|
|
29
29
|
this.predictions = new PredictionsAPI(this);
|
|
30
30
|
this.wallet = new WalletAPI(this);
|
|
31
|
+
this.lottery = new LotteryAPI(this);
|
|
31
32
|
}
|
|
32
33
|
// ==========================================================
|
|
33
34
|
// Internal HTTP layer
|
|
@@ -198,6 +199,77 @@ var WalletAPI = class {
|
|
|
198
199
|
async getWithdrawalFees(currency, amount) {
|
|
199
200
|
return this.client.request("GET", `/partner/wallet/withdrawal-fees?currency=${currency}&amount=${amount}`);
|
|
200
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Withdraw from omnibus balance.
|
|
204
|
+
* Initiates a payout to the partner's configured bank account or crypto wallet.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const result = await puul.wallet.withdraw({
|
|
209
|
+
* amount: 500000, // $5,000 in cents
|
|
210
|
+
* currency: 'USDC',
|
|
211
|
+
* method: 'bank', // or 'crypto'
|
|
212
|
+
* });
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
async withdraw(params) {
|
|
216
|
+
return this.client.request("POST", "/partner/wallet/withdraw", params);
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
var LotteryAPI = class {
|
|
220
|
+
constructor(client) {
|
|
221
|
+
this.client = client;
|
|
222
|
+
}
|
|
223
|
+
/** List lottery pools, optionally filtered by status and frequency */
|
|
224
|
+
async listPools(options) {
|
|
225
|
+
const params = new URLSearchParams();
|
|
226
|
+
if (options?.status) params.set("status", options.status);
|
|
227
|
+
if (options?.frequency) params.set("frequency", options.frequency);
|
|
228
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
229
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
230
|
+
return this.client.request("GET", `/partner/lottery/pools${query}`);
|
|
231
|
+
}
|
|
232
|
+
/** Get a specific pool by ID */
|
|
233
|
+
async getPool(poolId) {
|
|
234
|
+
return this.client.request("GET", `/partner/lottery/pools/${poolId}`);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Buy ticket(s) for a linked user.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const result = await puul.lottery.buyTicket('pool-uuid', {
|
|
242
|
+
* userId: 'puul-user-uuid',
|
|
243
|
+
* idempotencyKey: 'lottery-user456-pool1-001',
|
|
244
|
+
* quantity: 3,
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
async buyTicket(poolId, params) {
|
|
249
|
+
return this.client.request("POST", `/partner/lottery/pools/${poolId}/buy`, {
|
|
250
|
+
user_id: params.userId,
|
|
251
|
+
idempotency_key: params.idempotencyKey,
|
|
252
|
+
quantity: params.quantity,
|
|
253
|
+
user_external_id: params.userExternalId
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/** List lottery entries for your partner account */
|
|
257
|
+
async listEntries(options) {
|
|
258
|
+
const params = new URLSearchParams();
|
|
259
|
+
if (options?.poolId) params.set("pool_id", options.poolId);
|
|
260
|
+
if (options?.status) params.set("status", options.status);
|
|
261
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
262
|
+
const query = params.toString() ? `?${params.toString()}` : "";
|
|
263
|
+
return this.client.request("GET", `/partner/lottery/entries${query}`);
|
|
264
|
+
}
|
|
265
|
+
/** Get a single lottery entry by ID */
|
|
266
|
+
async getEntry(entryId) {
|
|
267
|
+
return this.client.request("GET", `/partner/lottery/entries/${entryId}`);
|
|
268
|
+
}
|
|
269
|
+
/** Get draw results for a completed pool */
|
|
270
|
+
async getDrawResults(poolId) {
|
|
271
|
+
return this.client.request("GET", `/partner/lottery/pools/${poolId}/results`);
|
|
272
|
+
}
|
|
201
273
|
};
|
|
202
274
|
|
|
203
275
|
// src/webhooks.ts
|
|
@@ -224,7 +296,7 @@ function parseWebhookEvent(body) {
|
|
|
224
296
|
}
|
|
225
297
|
const event = body;
|
|
226
298
|
if (typeof event.event !== "string") {
|
|
227
|
-
throw new
|
|
299
|
+
throw new TypeError('Invalid webhook body: missing "event" field');
|
|
228
300
|
}
|
|
229
301
|
return {
|
|
230
302
|
event: event.event,
|
|
@@ -232,17 +304,65 @@ function parseWebhookEvent(body) {
|
|
|
232
304
|
data: event.data || {}
|
|
233
305
|
};
|
|
234
306
|
}
|
|
307
|
+
function isPredictionPlacedEvent(event) {
|
|
308
|
+
return event.event === "prediction.placed";
|
|
309
|
+
}
|
|
235
310
|
function isPredictionSettledEvent(event) {
|
|
236
311
|
return event.event === "prediction.settled";
|
|
237
312
|
}
|
|
313
|
+
function isPredictionVoidedEvent(event) {
|
|
314
|
+
return event.event === "prediction.voided";
|
|
315
|
+
}
|
|
316
|
+
function isMarketClosedEvent(event) {
|
|
317
|
+
return event.event === "market.closed";
|
|
318
|
+
}
|
|
319
|
+
function isMarketSettledEvent(event) {
|
|
320
|
+
return event.event === "market.settled";
|
|
321
|
+
}
|
|
322
|
+
function isDepositConfirmedEvent(event) {
|
|
323
|
+
return event.event === "deposit.confirmed";
|
|
324
|
+
}
|
|
325
|
+
function isWithdrawalCompletedEvent(event) {
|
|
326
|
+
return event.event === "withdrawal.completed";
|
|
327
|
+
}
|
|
328
|
+
function isWithdrawalFailedEvent(event) {
|
|
329
|
+
return event.event === "withdrawal.failed";
|
|
330
|
+
}
|
|
331
|
+
function isLotteryPoolDrawnEvent(event) {
|
|
332
|
+
return event.event === "lottery.pool.drawn";
|
|
333
|
+
}
|
|
334
|
+
function isLotteryTicketWonEvent(event) {
|
|
335
|
+
return event.event === "lottery.ticket.won";
|
|
336
|
+
}
|
|
238
337
|
function asPredictionSettledData(event) {
|
|
239
338
|
return event.data;
|
|
240
339
|
}
|
|
340
|
+
function asMarketSettledData(event) {
|
|
341
|
+
return event.data;
|
|
342
|
+
}
|
|
343
|
+
function asLotteryPoolDrawnData(event) {
|
|
344
|
+
return event.data;
|
|
345
|
+
}
|
|
346
|
+
function asLotteryTicketWonData(event) {
|
|
347
|
+
return event.data;
|
|
348
|
+
}
|
|
241
349
|
export {
|
|
242
350
|
PuulError,
|
|
243
351
|
PuulPartner,
|
|
352
|
+
asLotteryPoolDrawnData,
|
|
353
|
+
asLotteryTicketWonData,
|
|
354
|
+
asMarketSettledData,
|
|
244
355
|
asPredictionSettledData,
|
|
356
|
+
isDepositConfirmedEvent,
|
|
357
|
+
isLotteryPoolDrawnEvent,
|
|
358
|
+
isLotteryTicketWonEvent,
|
|
359
|
+
isMarketClosedEvent,
|
|
360
|
+
isMarketSettledEvent,
|
|
361
|
+
isPredictionPlacedEvent,
|
|
245
362
|
isPredictionSettledEvent,
|
|
363
|
+
isPredictionVoidedEvent,
|
|
364
|
+
isWithdrawalCompletedEvent,
|
|
365
|
+
isWithdrawalFailedEvent,
|
|
246
366
|
parseWebhookEvent,
|
|
247
367
|
verifyWebhookSignature
|
|
248
368
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puul/partner-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Official TypeScript SDK for the Puul Partner API — integrate prediction markets into your platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -42,4 +42,4 @@
|
|
|
42
42
|
"engines": {
|
|
43
43
|
"node": ">=18.0.0"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
}
|