@@ -6,6 +6,14 @@ import type { ShapeSpec } from "./shapes/types.js";
66import { HttpClient } from "./utils/http.js" ;
77import { unflattenResponse } from "./utils/unflatten.js" ;
88import { PaginatedResponse , TangoClientOptions } from "./types.js" ;
9+ import type {
10+ WebhookEndpoint ,
11+ WebhookEventTypesResponse ,
12+ WebhookSamplePayloadResponse ,
13+ WebhookSubscription ,
14+ WebhookSubscriptionPayload ,
15+ WebhookTestDeliveryResult ,
16+ } from "./models/Webhooks.js" ;
917
1018type AnyRecord = Record < string , unknown > ;
1119
@@ -99,6 +107,11 @@ export interface ListEntitiesOptions extends ListOptionsBase {
99107 [ key : string ] : unknown ;
100108}
101109
110+ export interface ListWebhookSubscriptionsOptions {
111+ page ?: number ;
112+ pageSize ?: number ;
113+ }
114+
102115export class TangoClient {
103116 private readonly http : HttpClient ;
104117 private readonly shapeParser : ShapeParser ;
@@ -403,6 +416,101 @@ export class TangoClient {
403416 return paginated ;
404417 }
405418
419+ // ---------------------------------------------------------------------------
420+ // Webhooks (v2)
421+ // ---------------------------------------------------------------------------
422+
423+ async listWebhookEventTypes ( ) : Promise < WebhookEventTypesResponse > {
424+ return await this . http . get < WebhookEventTypesResponse > ( "/api/webhooks/event-types/" ) ;
425+ }
426+
427+ async listWebhookSubscriptions ( options : ListWebhookSubscriptionsOptions = { } ) : Promise < PaginatedResponse < WebhookSubscription > > {
428+ const { page = 1 , pageSize } = options ;
429+ const params : AnyRecord = { page } ;
430+ if ( pageSize !== undefined ) params . page_size = pageSize ;
431+
432+ const data = await this . http . get < AnyRecord > ( "/api/webhooks/subscriptions/" , params ) ;
433+ return buildPaginatedResponse < WebhookSubscription > ( data ) ;
434+ }
435+
436+ async getWebhookSubscription ( id : string ) : Promise < WebhookSubscription > {
437+ if ( ! id ) throw new TangoValidationError ( "Webhook subscription id is required" ) ;
438+ return await this . http . get < WebhookSubscription > ( `/api/webhooks/subscriptions/${ encodeURIComponent ( id ) } /` ) ;
439+ }
440+
441+ async createWebhookSubscription ( options : { subscriptionName : string ; payload : WebhookSubscriptionPayload } ) : Promise < WebhookSubscription > {
442+ const { subscriptionName, payload } = options ;
443+ if ( ! subscriptionName ) throw new TangoValidationError ( "Webhook subscriptionName is required" ) ;
444+ return await this . http . post < WebhookSubscription > ( "/api/webhooks/subscriptions/" , {
445+ subscription_name : subscriptionName ,
446+ payload,
447+ } ) ;
448+ }
449+
450+ async updateWebhookSubscription (
451+ id : string ,
452+ options : { subscriptionName ?: string ; payload ?: WebhookSubscriptionPayload } ,
453+ ) : Promise < WebhookSubscription > {
454+ if ( ! id ) throw new TangoValidationError ( "Webhook subscription id is required" ) ;
455+ const body : AnyRecord = { } ;
456+ if ( options . subscriptionName !== undefined ) body . subscription_name = options . subscriptionName ;
457+ if ( options . payload !== undefined ) body . payload = options . payload ;
458+ return await this . http . patch < WebhookSubscription > ( `/api/webhooks/subscriptions/${ encodeURIComponent ( id ) } /` , body ) ;
459+ }
460+
461+ async deleteWebhookSubscription ( id : string ) : Promise < void > {
462+ if ( ! id ) throw new TangoValidationError ( "Webhook subscription id is required" ) ;
463+ await this . http . delete ( `/api/webhooks/subscriptions/${ encodeURIComponent ( id ) } /` ) ;
464+ }
465+
466+ async listWebhookEndpoints ( options : { page ?: number ; limit ?: number } = { } ) : Promise < PaginatedResponse < WebhookEndpoint > > {
467+ const { page = 1 , limit = 25 } = options ;
468+ const params : AnyRecord = { page, limit : Math . min ( limit , 100 ) } ;
469+ const data = await this . http . get < AnyRecord > ( "/api/webhooks/endpoints/" , params ) ;
470+
471+ // Endpoints are commonly paginated like other Tango resources, but keep this resilient.
472+ if ( Array . isArray ( data ) ) {
473+ return { count : data . length , next : null , previous : null , pageMetadata : null , results : data as WebhookEndpoint [ ] } ;
474+ }
475+ return buildPaginatedResponse < WebhookEndpoint > ( data ) ;
476+ }
477+
478+ async getWebhookEndpoint ( id : string ) : Promise < WebhookEndpoint > {
479+ if ( ! id ) throw new TangoValidationError ( "Webhook endpoint id is required" ) ;
480+ return await this . http . get < WebhookEndpoint > ( `/api/webhooks/endpoints/${ encodeURIComponent ( id ) } /` ) ;
481+ }
482+
483+ async createWebhookEndpoint ( options : { callbackUrl : string ; isActive ?: boolean } ) : Promise < WebhookEndpoint > {
484+ const { callbackUrl, isActive = true } = options ;
485+ if ( ! callbackUrl ) throw new TangoValidationError ( "Webhook callbackUrl is required" ) ;
486+ return await this . http . post < WebhookEndpoint > ( "/api/webhooks/endpoints/" , { callback_url : callbackUrl , is_active : isActive } ) ;
487+ }
488+
489+ async updateWebhookEndpoint ( id : string , options : { callbackUrl ?: string ; isActive ?: boolean } ) : Promise < WebhookEndpoint > {
490+ if ( ! id ) throw new TangoValidationError ( "Webhook endpoint id is required" ) ;
491+ const body : AnyRecord = { } ;
492+ if ( options . callbackUrl !== undefined ) body . callback_url = options . callbackUrl ;
493+ if ( options . isActive !== undefined ) body . is_active = options . isActive ;
494+ return await this . http . patch < WebhookEndpoint > ( `/api/webhooks/endpoints/${ encodeURIComponent ( id ) } /` , body ) ;
495+ }
496+
497+ async deleteWebhookEndpoint ( id : string ) : Promise < void > {
498+ if ( ! id ) throw new TangoValidationError ( "Webhook endpoint id is required" ) ;
499+ await this . http . delete ( `/api/webhooks/endpoints/${ encodeURIComponent ( id ) } /` ) ;
500+ }
501+
502+ async testWebhookDelivery ( options : { endpointId ?: string } = { } ) : Promise < WebhookTestDeliveryResult > {
503+ const body : AnyRecord = { } ;
504+ if ( options . endpointId ) body . endpoint_id = options . endpointId ;
505+ return await this . http . post < WebhookTestDeliveryResult > ( "/api/webhooks/endpoints/test-delivery/" , body ) ;
506+ }
507+
508+ async getWebhookSamplePayload ( options : { eventType ?: string } = { } ) : Promise < WebhookSamplePayloadResponse > {
509+ const params : AnyRecord = { } ;
510+ if ( options . eventType ) params . event_type = options . eventType ;
511+ return await this . http . get < WebhookSamplePayloadResponse > ( "/api/webhooks/endpoints/sample-payload/" , params ) ;
512+ }
513+
406514 private parseShape ( shape : string | null | undefined , flat : boolean , flatLists : boolean ) : ShapeSpec | null {
407515 if ( ! shape ) return null ;
408516 return this . shapeParser . parseWithFlags ( shape , flat , flatLists ) ;
0 commit comments