{"record":{"id":"7f90038d9d777896","repo":"calcom/cal.diy","slug":"webhook-with-this-subscriber-url-already-exists-fo","errorCode":null,"errorMessage":"Webhook with this subscriber url already exists for this event type","messagePattern":"Webhook with this subscriber url already exists for this event type","errorType":"http","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"apps/api/v2/src/modules/webhooks/services/event-type-webhooks.service.ts","lineNumber":26,"sourceCode":"@Injectable()\nexport class EventTypeWebhooksService {\n  constructor(private readonly webhooksRepository: WebhooksRepository) {}\n\n  async createEventTypeWebhook(eventTypeId: number, body: PipedInputWebhookType) {\n    validateWebhookUrl(body.subscriberUrl);\n\n    if (body.eventTriggers.includes(WebhookTriggerEvents.DELEGATION_CREDENTIAL_ERROR)) {\n      throw new BadRequestException(\n        \"DELEGATION_CREDENTIAL_ERROR trigger is only available for organization webhooks\"\n      );\n    }\n\n    const existingWebhook = await this.webhooksRepository.getEventTypeWebhookByUrl(\n      eventTypeId,\n      body.subscriberUrl\n    );\n    if (existingWebhook) {\n      throw new ConflictException(\"Webhook with this subscriber url already exists for this event type\");\n    }\n    return this.webhooksRepository.createEventTypeWebhook(eventTypeId, {\n      ...body,\n      payloadTemplate: body.payloadTemplate ?? null,\n      secret: body.secret ?? null,\n    });\n  }\n\n  getEventTypeWebhooksPaginated(eventTypeId: number, skip: number, take: number) {\n    return this.webhooksRepository.getEventTypeWebhooksPaginated(eventTypeId, skip, take);\n  }\n\n  async deleteAllEventTypeWebhooks(eventTypeId: number): Promise<{ count: number }> {\n    return this.webhooksRepository.deleteAllEventTypeWebhooks(eventTypeId);\n  }\n}\n","sourceCodeStart":8,"sourceCodeEnd":43,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/webhooks/services/event-type-webhooks.service.ts#L8-L43","documentation":"EventTypeWebhooksService.createEventTypeWebhook queries getEventTypeWebhookByUrl(eventTypeId, subscriberUrl); if a row already exists with that URL for the same event type, it throws ConflictException (HTTP 409). The (eventTypeId, subscriberUrl) pair is treated as unique.","triggerScenarios":"POSTing a webhook with a subscriberUrl that already exists for the same eventTypeId. Replaying a successful request, retrying after a timeout, or two clients registering the same callback URL.","commonSituations":"Idempotency-unaware retry logic; multiple integrations pointing at the same callback endpoint; development where the same ngrok URL is reused across attempts.","solutions":["Before creating, call the paginated list endpoint and check whether the subscriberUrl is already registered for this event type.","Use a unique subscriberUrl per webhook (e.g. append a unique path segment).","Treat HTTP 409 as 'already exists' and continue idempotently instead of erroring.","De-duplicate retry payloads by subscriberUrl."],"exampleFix":"// before\nawait api.createEventTypeWebhook(eventTypeId, { subscriberUrl, ... });\n// after\nconst existing = await api.listEventTypeWebhooks(eventTypeId);\nif (existing.find(w => w.subscriberUrl === subscriberUrl)) return existing.find(w => w.subscriberUrl === subscriberUrl);\nawait api.createEventTypeWebhook(eventTypeId, { subscriberUrl, ... });","handlingStrategy":"validation","validationCode":"async function createIfMissingEventType(api, eventTypeId, body) {\n  const list = await api.getEventTypeWebhooksPaginated(eventTypeId, 0, 1000);\n  if (list.find(w => w.subscriberUrl === body.subscriberUrl)) return;\n  return api.createEventTypeWebhook(eventTypeId, body);\n}","typeGuard":"const isDuplicateUrl = (list: { subscriberUrl: string }[], url: string): boolean =>\n  list.some(w => w.subscriberUrl === url);","tryCatchPattern":"try { await api.createEventTypeWebhook(eventTypeId, body); }\ncatch (e) {\n  if (e.status === 409) { /* treat as already registered, continue */ }\n  else throw e;\n}","preventionTips":["Make subscriber URLs unique per registration.","Treat HTTP 409 as idempotent success in retry logic.","Pre-list webhooks before creating to avoid duplicate-trigger retries."],"tags":["webhooks","conflict","duplicate","event-type"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}