{"record":{"id":"25aa49213ee8b0e9","repo":"calcom/cal.diy","slug":"webhook-with-this-subscriber-url-already-exists-fo-25aa49","errorCode":null,"errorMessage":"Webhook with this subscriber url already exists for this user","messagePattern":"Webhook with this subscriber url already exists for this user","errorType":"http","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"apps/api/v2/src/modules/webhooks/services/user-webhooks.service.ts","lineNumber":23,"sourceCode":"\nimport { WebhookTriggerEvents } from \"@calcom/prisma/enums\";\n\n@Injectable()\nexport class UserWebhooksService {\n  constructor(private readonly webhooksRepository: WebhooksRepository) {}\n\n  async createUserWebhook(userId: 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.getUserWebhookByUrl(userId, body.subscriberUrl);\n    if (existingWebhook) {\n      throw new ConflictException(\"Webhook with this subscriber url already exists for this user\");\n    }\n\n    return this.webhooksRepository.createUserWebhook(userId, {\n      ...body,\n      payloadTemplate: body.payloadTemplate ?? null,\n      secret: body.secret ?? null,\n    });\n  }\n\n  async getUserWebhooksPaginated(userId: number, skip: number, take: number) {\n    return this.webhooksRepository.getUserWebhooksPaginated(userId, skip, take);\n  }\n}\n","sourceCodeStart":5,"sourceCodeEnd":37,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/webhooks/services/user-webhooks.service.ts#L5-L37","documentation":"UserWebhooksService.createUserWebhook calls getUserWebhookByUrl(userId, subscriberUrl); if a row exists for that user+URL it throws ConflictException (HTTP 409). The (userId, subscriberUrl) pair is unique.","triggerScenarios":"POSTing a user webhook with a subscriberUrl already registered for the same userId.","commonSituations":"Retry after a successful create; single callback endpoint reused across integrations for one user; dev URL reuse.","solutions":["List the user's webhooks and check subscriberUrl before creating.","Use unique subscriber URLs per webhook.","Handle 409 as 'already registered' idempotently."],"exampleFix":"// before\nawait api.createUserWebhook(userId, { subscriberUrl, ... });\n// after\nconst list = await api.listUserWebhooks(userId);\nif (list.find(w => w.subscriberUrl === subscriberUrl)) return;\nawait api.createUserWebhook(userId, { subscriberUrl, ... });","handlingStrategy":"validation","validationCode":"async function createIfMissingUser(api, userId, body) {\n  const list = await api.getUserWebhooksPaginated(userId, 0, 1000);\n  if (list.find(w => w.subscriberUrl === body.subscriberUrl)) return;\n  return api.createUserWebhook(userId, body);\n}","typeGuard":"const isDuplicateUrl = (list: { subscriberUrl: string }[], url: string): boolean =>\n  list.some(w => w.subscriberUrl === url);","tryCatchPattern":"try { await api.createUserWebhook(userId, body); }\ncatch (e) { if (e.status === 409) return; else throw e; }","preventionTips":["Pre-list user webhooks before creating.","Use unique subscriber URLs per user webhook.","Idempotently absorb 409."],"tags":["webhooks","conflict","duplicate","user"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}