ticketnation-sdk 1.0.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 ADDED
@@ -0,0 +1,208 @@
1
+ # @ticketnation/sdk
2
+
3
+ Official TypeScript SDK for the [Ticketnation](https://ticketnation.ph) Open API. Publish events, manage tickets, receive orders, and search venues programmatically.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @ticketnation/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { Ticketnation } from '@ticketnation/sdk';
15
+
16
+ const tn = new Ticketnation({
17
+ apiKey: 'tn_live_your_api_key_here',
18
+ });
19
+
20
+ // Create an event with tickets
21
+ const event = await tn.events.create({
22
+ name: 'Summer Music Fest 2025',
23
+ dateTime: '2025-06-15T18:00:00.000Z',
24
+ venueId: 'uuid-venue-id',
25
+ tickets: [
26
+ { name: 'General Admission', price: 150000, quantity: 500 },
27
+ { name: 'VIP', price: 500000, quantity: 50 },
28
+ ],
29
+ });
30
+
31
+ // Publish it
32
+ await tn.events.publish(event.id);
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ ```typescript
38
+ const tn = new Ticketnation({
39
+ apiKey: 'tn_live_...', // Required
40
+ baseUrl: 'http://localhost:4000', // Default: https://api.ticketnation.ph
41
+ timeout: 30000, // Default: 30s
42
+ retries: 2, // Default: 2 (retries on 5xx only)
43
+ debug: false, // Default: false (logs redacted requests)
44
+ });
45
+ ```
46
+
47
+ ## API Reference
48
+
49
+ ### Account
50
+
51
+ ```typescript
52
+ // Get API key info and organization details
53
+ const info = await tn.me();
54
+ // → { apiKey: { id, name, scopes, ... }, organization: { id, name, slug } }
55
+ ```
56
+
57
+ ### Events
58
+
59
+ ```typescript
60
+ // Create
61
+ const event = await tn.events.create({ name: '...', dateTime: '...' });
62
+
63
+ // List (paginated)
64
+ const { data, meta } = await tn.events.list({ page: 1, take: 10, status: 'PUBLISHED' });
65
+
66
+ // Get by ID or slug
67
+ const event = await tn.events.get('summer-music-fest-2025');
68
+
69
+ // Update
70
+ const updated = await tn.events.update(eventId, { name: 'New Name' });
71
+
72
+ // Lifecycle
73
+ await tn.events.publish(eventId);
74
+ await tn.events.unpublish(eventId);
75
+ await tn.events.archive(eventId);
76
+
77
+ // Delete (DRAFT only, no sold tickets)
78
+ await tn.events.delete(eventId);
79
+ ```
80
+
81
+ ### Tickets
82
+
83
+ ```typescript
84
+ // Create a ticket type for an event
85
+ const ticket = await tn.tickets.create(eventId, {
86
+ name: 'VIP Pass',
87
+ price: 500000, // in centavos (5,000.00 PHP)
88
+ quantity: 100,
89
+ });
90
+
91
+ // List all ticket types
92
+ const tickets = await tn.tickets.list(eventId);
93
+
94
+ // Get single ticket
95
+ const ticket = await tn.tickets.get(eventId, ticketId);
96
+
97
+ // Update price or quantity
98
+ await tn.tickets.update(eventId, ticketId, { price: 450000 });
99
+
100
+ // Publish (make available for sale)
101
+ await tn.tickets.publish(eventId, ticketId);
102
+
103
+ // Mark as sold out (sets remainingQuantity to 0)
104
+ await tn.tickets.markSoldOut(eventId, ticketId);
105
+
106
+ // Delete (only if no tickets sold)
107
+ await tn.tickets.delete(eventId, ticketId);
108
+ ```
109
+
110
+ ### Orders
111
+
112
+ ```typescript
113
+ // List orders for an event (paginated)
114
+ const { data, meta } = await tn.orders.list(eventId, { page: 1, status: 'COMPLETED' });
115
+
116
+ // Get order details (includes line items and payment info)
117
+ const order = await tn.orders.get(orderId);
118
+ ```
119
+
120
+ ### Venues
121
+
122
+ ```typescript
123
+ // Search venues by name
124
+ const { data, meta } = await tn.venues.search({ query: 'MOA Arena' });
125
+ // Use venue.id when creating events with locationType: 'VENUE'
126
+ ```
127
+
128
+ ## Pagination Helper
129
+
130
+ For iterating through all pages automatically:
131
+
132
+ ```typescript
133
+ import { Ticketnation, paginate, fetchAllPages } from '@ticketnation/sdk';
134
+
135
+ const tn = new Ticketnation({ apiKey: '...' });
136
+
137
+ // Async iterator — processes one page at a time
138
+ for await (const batch of paginate((p) => tn.events.list(p))) {
139
+ console.log(`Got ${batch.length} events`);
140
+ }
141
+
142
+ // Fetch all at once
143
+ const allEvents = await fetchAllPages((p) => tn.events.list(p));
144
+ ```
145
+
146
+ ## Error Handling
147
+
148
+ All API errors throw `TicketnationError` with structured details:
149
+
150
+ ```typescript
151
+ import { Ticketnation, TicketnationError } from '@ticketnation/sdk';
152
+
153
+ try {
154
+ await tn.events.get('nonexistent');
155
+ } catch (error) {
156
+ if (error instanceof TicketnationError) {
157
+ console.log(error.code); // 'NOT_FOUND'
158
+ console.log(error.status); // 404
159
+ console.log(error.message); // 'Event not found: nonexistent'
160
+ console.log(error.requestId); // 'req_a1b2c3d4' (for support)
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Error Codes
166
+
167
+ | Code | Status | Description |
168
+ |------|--------|-------------|
169
+ | `VALIDATION_ERROR` | 400 | Invalid input — check `error.details` for field-level errors |
170
+ | `UNAUTHORIZED` | 401 | Missing or invalid API key |
171
+ | `FORBIDDEN` | 403 | API key lacks required scope |
172
+ | `NOT_FOUND` | 404 | Resource not found or not owned by your organization |
173
+ | `RATE_LIMITED` | 429 | Too many requests — SDK auto-retries on 5xx, not 429 |
174
+ | `INTERNAL_ERROR` | 500 | Server error — SDK auto-retries up to `retries` times |
175
+ | `TIMEOUT` | 0 | Request exceeded `timeout` ms |
176
+ | `NETWORK_ERROR` | 0 | DNS, connection, or other network failure |
177
+
178
+ ## Scopes
179
+
180
+ Your API key needs the right scopes for each operation:
181
+
182
+ | Scope | Operations |
183
+ |-------|------------|
184
+ | `events:read` | List/get events, search venues |
185
+ | `events:write` | Create/update/publish/delete events |
186
+ | `tickets:read` | List/get tickets |
187
+ | `tickets:write` | Create/update/publish/delete/sold-out tickets |
188
+ | `orders:read` | List/get orders |
189
+ | `webhooks:manage` | Create/update/delete webhooks |
190
+
191
+ ## Authentication
192
+
193
+ Get your API key from **Organizer Dashboard > Settings > API Keys**.
194
+
195
+ The SDK sends the key via the `api-key` HTTP header. Keys are scoped to a single organization.
196
+
197
+ ## Requirements
198
+
199
+ - Node.js 18+ (uses native `fetch`)
200
+ - TypeScript 5.0+ (optional but recommended)
201
+
202
+ ## Full Documentation
203
+
204
+ For complete REST API reference with `curl` examples, webhook setup, and architecture overview, visit the [Ticketnation Developer Docs](https://docs.ticketnation.ph/developers/overview).
205
+
206
+ ## License
207
+
208
+ MIT
@@ -0,0 +1,372 @@
1
+ interface ClientConfig {
2
+ apiKey: string;
3
+ baseUrl: string;
4
+ timeout: number;
5
+ retries: number;
6
+ debug: boolean;
7
+ }
8
+ declare class HttpClient {
9
+ private readonly config;
10
+ constructor(config: ClientConfig);
11
+ request<T>(method: string, path: string, opts?: {
12
+ body?: unknown;
13
+ params?: Record<string, unknown>;
14
+ }): Promise<T>;
15
+ private doRequest;
16
+ private buildUrl;
17
+ private sleep;
18
+ }
19
+
20
+ interface TicketNationConfig {
21
+ apiKey: string;
22
+ baseUrl?: string;
23
+ timeout?: number;
24
+ retries?: number;
25
+ debug?: boolean;
26
+ }
27
+ interface PaginationMeta {
28
+ page: number;
29
+ take: number;
30
+ total: number;
31
+ totalPages: number;
32
+ }
33
+ interface PaginatedResponse<T> {
34
+ data: T[];
35
+ meta: PaginationMeta;
36
+ }
37
+ interface DataResponse<T> {
38
+ data: T;
39
+ }
40
+ interface PaginationParams {
41
+ page?: number;
42
+ take?: number;
43
+ }
44
+ type EventStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';
45
+ type EventType = 'PAID' | 'FREE';
46
+ type EventJourneyType = 'STANDARD' | 'RSVP' | 'PRESELLING';
47
+ type EventLocationType = 'VENUE' | 'ONLINE';
48
+ type EventVisibility = 'PUBLIC' | 'PRIVATE';
49
+ interface Event {
50
+ id: string;
51
+ name: string;
52
+ description: string | null;
53
+ dateTime: string;
54
+ endDateTime: string | null;
55
+ status: EventStatus;
56
+ type: EventType;
57
+ journeyType: EventJourneyType;
58
+ currency: string;
59
+ locationType: EventLocationType;
60
+ visibility: EventVisibility;
61
+ eventCapacity: number | null;
62
+ timezone: string;
63
+ absorbFees: boolean;
64
+ callbackUrl: string | null;
65
+ slug: string;
66
+ eventTickets: Ticket[];
67
+ venue: VenueRef | null;
68
+ slugV2: {
69
+ slug: string;
70
+ } | null;
71
+ }
72
+ interface CreateEventParams {
73
+ name: string;
74
+ description?: string;
75
+ dateTime: string;
76
+ endDateTime?: string;
77
+ start?: string;
78
+ end?: string;
79
+ type?: EventType;
80
+ journeyType?: EventJourneyType;
81
+ currency?: string;
82
+ locationType?: EventLocationType;
83
+ onlineMeetingUrl?: string;
84
+ onlineMeetingProvider?: string;
85
+ eventCapacity?: number;
86
+ visibility?: EventVisibility;
87
+ eventTicketLimit?: number;
88
+ timezone?: string;
89
+ absorbFees?: boolean;
90
+ callbackUrl?: string;
91
+ venueId?: string;
92
+ tickets?: CreateTicketParams[];
93
+ }
94
+ interface UpdateEventParams {
95
+ name?: string;
96
+ description?: string;
97
+ dateTime?: string;
98
+ endDateTime?: string;
99
+ start?: string;
100
+ end?: string;
101
+ type?: EventType;
102
+ journeyType?: EventJourneyType;
103
+ currency?: string;
104
+ locationType?: EventLocationType;
105
+ onlineMeetingUrl?: string;
106
+ onlineMeetingProvider?: string;
107
+ eventCapacity?: number;
108
+ visibility?: EventVisibility;
109
+ eventTicketLimit?: number;
110
+ timezone?: string;
111
+ absorbFees?: boolean;
112
+ callbackUrl?: string;
113
+ venueId?: string;
114
+ }
115
+ interface ListEventsParams extends PaginationParams {
116
+ status?: EventStatus;
117
+ search?: string;
118
+ }
119
+ type TicketSeatType = 'GENERAL_ADMISSION' | 'RESERVED_SEAT' | 'VIP';
120
+ type TicketStatus = 'ACTIVE' | 'INACTIVE';
121
+ interface Ticket {
122
+ id: string;
123
+ name: string;
124
+ description: string | null;
125
+ price: number;
126
+ originalPrice: number;
127
+ quantity: number;
128
+ remainingQuantity: number;
129
+ section: string;
130
+ row: string;
131
+ sectionGroup: string | null;
132
+ type: TicketSeatType;
133
+ status: TicketStatus;
134
+ published: boolean;
135
+ minimumPurchaseQuantity: number | null;
136
+ maximumPurchaseQuantity: number | null;
137
+ requiresApproval: boolean;
138
+ deliveryMethod: string;
139
+ eventId?: string;
140
+ createdAt?: string;
141
+ updatedAt?: string;
142
+ }
143
+ interface CreateTicketParams {
144
+ name: string;
145
+ description?: string;
146
+ price: number;
147
+ quantity: number;
148
+ section?: string;
149
+ row?: string;
150
+ sectionGroup?: string;
151
+ type?: TicketSeatType;
152
+ minimumPurchaseQuantity?: number;
153
+ maximumPurchaseQuantity?: number;
154
+ requiresApproval?: boolean;
155
+ published?: boolean;
156
+ }
157
+ interface UpdateTicketParams {
158
+ name?: string;
159
+ description?: string;
160
+ price?: number;
161
+ quantity?: number;
162
+ section?: string;
163
+ row?: string;
164
+ sectionGroup?: string;
165
+ type?: TicketSeatType;
166
+ minimumPurchaseQuantity?: number;
167
+ maximumPurchaseQuantity?: number;
168
+ requiresApproval?: boolean;
169
+ published?: boolean;
170
+ }
171
+ type OrderStatus = 'PENDING' | 'COMPLETED' | 'CANCELLED' | 'REFUNDED';
172
+ interface OrderItemTicket {
173
+ id: string;
174
+ name: string;
175
+ section: string;
176
+ }
177
+ interface OrderItem {
178
+ id: string;
179
+ quantity: number;
180
+ price: number;
181
+ eventTicket: OrderItemTicket | null;
182
+ }
183
+ interface OrderPayment {
184
+ id: string;
185
+ status: string;
186
+ method: string | null;
187
+ paidAt: string | null;
188
+ }
189
+ interface Order {
190
+ id: string;
191
+ orderNumber: string;
192
+ status: OrderStatus;
193
+ totalAmount: number;
194
+ currency: string;
195
+ quantity: number;
196
+ buyerName: string | null;
197
+ buyerEmail: string | null;
198
+ createdAt: string;
199
+ updatedAt: string;
200
+ eventId: string;
201
+ orderItems: OrderItem[];
202
+ payment?: OrderPayment | null;
203
+ }
204
+ interface ListOrdersParams extends PaginationParams {
205
+ status?: OrderStatus;
206
+ }
207
+ interface VenueRef {
208
+ id: string;
209
+ name: string;
210
+ address1: string | null;
211
+ }
212
+ interface Venue {
213
+ id: string;
214
+ name: string;
215
+ address1: string | null;
216
+ address2: string | null;
217
+ city: string | null;
218
+ state: string | null;
219
+ country: string | null;
220
+ zipCode: string | null;
221
+ latitude: number | null;
222
+ longitude: number | null;
223
+ }
224
+ interface SearchVenuesParams extends PaginationParams {
225
+ query: string;
226
+ }
227
+ type WebhookEventType = 'order.completed' | 'order.refunded' | 'event.sold_out' | 'ticket.inventory_low';
228
+ interface Webhook {
229
+ id: string;
230
+ url: string;
231
+ events: WebhookEventType[];
232
+ isActive: boolean;
233
+ failureCount: number;
234
+ lastTriggeredAt: string | null;
235
+ lastFailedAt: string | null;
236
+ createdAt: string;
237
+ updatedAt: string;
238
+ }
239
+ interface WebhookWithSecret extends Webhook {
240
+ secret: string;
241
+ }
242
+ interface CreateWebhookParams {
243
+ url: string;
244
+ events: WebhookEventType[];
245
+ }
246
+ interface UpdateWebhookParams {
247
+ url?: string;
248
+ events?: WebhookEventType[];
249
+ isActive?: boolean;
250
+ }
251
+ interface ApiKeyInfo {
252
+ id: string;
253
+ name: string;
254
+ description: string | null;
255
+ scopes: string[];
256
+ callbackUrl: string | null;
257
+ createdAt: string;
258
+ expiresAt: string | null;
259
+ lastUsedAt: string | null;
260
+ }
261
+ interface OrganizationInfo {
262
+ id: string;
263
+ name: string;
264
+ slug: string | null;
265
+ }
266
+ interface AccountInfo {
267
+ apiKey: ApiKeyInfo;
268
+ organization: OrganizationInfo;
269
+ }
270
+ interface DeletedResponse {
271
+ deleted: boolean;
272
+ id: string;
273
+ }
274
+ interface ApiErrorBody {
275
+ code: string;
276
+ message: string;
277
+ details?: Array<{
278
+ field: string;
279
+ message: string;
280
+ }>;
281
+ }
282
+ interface ApiErrorResponse {
283
+ error: ApiErrorBody;
284
+ requestId: string;
285
+ }
286
+
287
+ declare class EventsResource {
288
+ private readonly client;
289
+ constructor(client: HttpClient);
290
+ create(params: CreateEventParams): Promise<Event>;
291
+ list(params?: ListEventsParams): Promise<PaginatedResponse<Event>>;
292
+ get(idOrSlug: string): Promise<Event>;
293
+ update(eventId: string, params: UpdateEventParams): Promise<Event>;
294
+ publish(eventId: string): Promise<Event>;
295
+ unpublish(eventId: string): Promise<Event>;
296
+ archive(eventId: string): Promise<Event>;
297
+ delete(eventId: string): Promise<DeletedResponse>;
298
+ }
299
+
300
+ declare class TicketsResource {
301
+ private readonly client;
302
+ constructor(client: HttpClient);
303
+ create(eventId: string, params: CreateTicketParams): Promise<Ticket>;
304
+ list(eventId: string): Promise<Ticket[]>;
305
+ get(eventId: string, ticketId: string): Promise<Ticket>;
306
+ update(eventId: string, ticketId: string, params: UpdateTicketParams): Promise<Ticket>;
307
+ publish(eventId: string, ticketId: string): Promise<Ticket>;
308
+ markSoldOut(eventId: string, ticketId: string): Promise<Ticket>;
309
+ delete(eventId: string, ticketId: string): Promise<DeletedResponse>;
310
+ }
311
+
312
+ declare class OrdersResource {
313
+ private readonly client;
314
+ constructor(client: HttpClient);
315
+ list(eventId: string, params?: ListOrdersParams): Promise<PaginatedResponse<Order>>;
316
+ get(orderId: string): Promise<Order>;
317
+ }
318
+
319
+ declare class VenuesResource {
320
+ private readonly client;
321
+ constructor(client: HttpClient);
322
+ search(params: SearchVenuesParams): Promise<PaginatedResponse<Venue>>;
323
+ }
324
+
325
+ declare class TicketNationError extends Error {
326
+ readonly code: string;
327
+ readonly status: number;
328
+ readonly requestId: string | null;
329
+ readonly details: Array<{
330
+ field: string;
331
+ message: string;
332
+ }> | undefined;
333
+ constructor(message: string, opts: {
334
+ code: string;
335
+ status: number;
336
+ requestId?: string;
337
+ details?: Array<{
338
+ field: string;
339
+ message: string;
340
+ }>;
341
+ });
342
+ static fromResponse(status: number, body: {
343
+ error: ApiErrorBody;
344
+ requestId?: string;
345
+ }): TicketNationError;
346
+ toJSON(): {
347
+ name: string;
348
+ code: string;
349
+ status: number;
350
+ message: string;
351
+ requestId: string | null;
352
+ details: {
353
+ field: string;
354
+ message: string;
355
+ }[] | undefined;
356
+ };
357
+ }
358
+
359
+ declare function paginate<T>(fetchPage: (params: PaginationParams) => Promise<PaginatedResponse<T>>, initialParams?: PaginationParams): AsyncGenerator<T[], void, undefined>;
360
+ declare function fetchAllPages<T>(fetchPage: (params: PaginationParams) => Promise<PaginatedResponse<T>>, initialParams?: PaginationParams): Promise<T[]>;
361
+
362
+ declare class TicketNation {
363
+ readonly events: EventsResource;
364
+ readonly tickets: TicketsResource;
365
+ readonly orders: OrdersResource;
366
+ readonly venues: VenuesResource;
367
+ private readonly client;
368
+ constructor(config: TicketNationConfig);
369
+ me(): Promise<AccountInfo>;
370
+ }
371
+
372
+ export { type AccountInfo, type ApiErrorBody, type ApiErrorResponse, type ApiKeyInfo, type CreateEventParams, type CreateTicketParams, type CreateWebhookParams, type DataResponse, type DeletedResponse, type Event, type EventJourneyType, type EventLocationType, type EventStatus, type EventType, type EventVisibility, type ListEventsParams, type ListOrdersParams, type Order, type OrderItem, type OrderItemTicket, type OrderPayment, type OrderStatus, type OrganizationInfo, type PaginatedResponse, type PaginationMeta, type PaginationParams, type SearchVenuesParams, type Ticket, TicketNation, type TicketNationConfig, TicketNationError, type TicketSeatType, type TicketStatus, type UpdateEventParams, type UpdateTicketParams, type UpdateWebhookParams, type Venue, type VenueRef, type Webhook, type WebhookEventType, type WebhookWithSecret, fetchAllPages, paginate };