{"record":{"id":"2d7c1ed8f619dbce","repo":"calcom/cal.diy","slug":"invoice-not-found","errorCode":null,"errorMessage":"Invoice not found","messagePattern":"Invoice not found","errorType":"http","errorClass":"HttpCode","httpStatus":204,"severity":"error","filePath":"packages/app-store/alby/api/webhook.ts","lineNumber":87,"sourceCode":"          },\n        },\n      },\n    });\n\n    if (!payment) throw new HttpCode({ statusCode: 204, message: \"Payment not found\" });\n    const key = payment.booking?.user?.credentials?.[0].key;\n    if (!key) throw new HttpCode({ statusCode: 204, message: \"Credentials not found\" });\n\n    const parseCredentials = albyCredentialKeysSchema.safeParse(key);\n    if (!parseCredentials.success) {\n      console.error(parseCredentials.error);\n      throw new HttpCode({ statusCode: 500, message: \"Credentials not valid\" });\n    }\n\n    const credentials = parseCredentials.data;\n\n    const albyInvoice = await parseInvoice(bodyAsString, parsedHeaders, credentials.webhook_endpoint_secret);\n    if (!albyInvoice) throw new HttpCode({ statusCode: 204, message: \"Invoice not found\" });\n    if (albyInvoice.amount !== payment.amount) {\n      throw new HttpCode({ statusCode: 400, message: \"invoice amount does not match payment amount\" });\n    }\n\n    const traceContext = distributedTracing.createTrace(\"alby_webhook\", {\n      meta: { paymentId: payment.id, bookingId: payment.bookingId },\n    });\n    return await handlePaymentSuccess({\n      paymentId: payment.id,\n      bookingId: payment.bookingId,\n      appSlug: \"alby\",\n      traceContext,\n    });\n  } catch (_err) {\n    const err = getServerErrorFromUnknown(_err);\n    console.error(`Webhook Error: ${err.message}`);\n    return res.status(err.statusCode).send({\n      message: err.message,","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/packages/app-store/alby/api/webhook.ts#L69-L105","documentation":"Thrown when parseInvoice returns null, which happens when Svix Webhook.verify throws inside parseInvoice - i.e. signature verification failed. The webhook_endpoint_secret stored on the credential does not match the secret Alby used to sign the event. Returns HTTP 204.","triggerScenarios":"webhook_endpoint_secret was rotated in Alby but not refreshed in cal.com; secret copied incorrectly; replay/tampering that breaks the signature; Alby sending events for a different webhook endpoint than the one whose secret is stored.","commonSituations":"Re-installing Alby creates a new endpoint with a new secret while the old credential key is retained; copy-paste error in the secret; multiple Alby endpoints sharing one credential.","solutions":["Confirm credentials.webhook_endpoint_secret matches the current Alby endpoint signing secret.","Re-run Alby setup to capture the latest endpoint secret into the credential.","Only treat the 204 as a benign 'duplicate webhook' after ruling out a secret mismatch."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const ok = parseInvoice(bodyAsString, parsedHeaders, credentials.webhook_endpoint_secret);\nif (!ok) {\n  // the stored secret likely differs from Alby's current signing secret\n}","typeGuard":"const isInvoice = (v: unknown): v is { amount: number } =>\n  typeof v === 'object' && v !== null && typeof (v as any).amount === 'number';","tryCatchPattern":null,"preventionTips":["Re-run Alby setup after rotating the Alby endpoint to refresh the secret.","Store the webhook_endpoint_secret exactly as Alby provides it.","Use one credential per Alby endpoint to avoid secret cross-talk."],"tags":["alby","webhook","svix","signature","secret-mismatch"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}