diff --git a/server/lib/billing/index.ts b/server/lib/billing/index.ts index 54c9ee2e0..1bc354f7e 100644 --- a/server/lib/billing/index.ts +++ b/server/lib/billing/index.ts @@ -3,3 +3,4 @@ export * from "./features"; export * from "./limitsService"; export * from "./getOrgTierData"; export * from "./createCustomer"; +export * from "./linkEmailOrg"; diff --git a/server/lib/billing/linkEmailOrg.ts b/server/lib/billing/linkEmailOrg.ts new file mode 100644 index 000000000..df67d2ed8 --- /dev/null +++ b/server/lib/billing/linkEmailOrg.ts @@ -0,0 +1,6 @@ +export async function linkEmailOrg( + orgId: string, + email: string | null | undefined +): Promise { + return; +} diff --git a/server/private/lib/billing/index.ts b/server/private/lib/billing/index.ts index 4d52668c0..0223b8aca 100644 --- a/server/private/lib/billing/index.ts +++ b/server/private/lib/billing/index.ts @@ -13,3 +13,4 @@ export * from "./getOrgTierData"; export * from "./createCustomer"; +export * from "./linkEmailOrg"; diff --git a/server/private/lib/billing/linkEmailOrg.ts b/server/private/lib/billing/linkEmailOrg.ts new file mode 100644 index 000000000..c14485a3d --- /dev/null +++ b/server/private/lib/billing/linkEmailOrg.ts @@ -0,0 +1,56 @@ +/* + * This file is part of a proprietary work. + * + * Copyright (c) 2025-2026 Fossorial, Inc. + * All rights reserved. + * + * This file is licensed under the Fossorial Commercial License. + * You may not use this file except in compliance with the License. + * Unauthorized use, copying, modification, or distribution is strictly prohibited. + * + * This file is not licensed under the AGPLv3. + */ + +import logger from "@server/logger"; +import privateConfig from "#private/lib/config"; +import { build } from "@server/build"; + +export async function linkEmailOrg( + orgId: string, + email: string | null | undefined +): Promise { + if (build !== "saas") { + return; + } + + if (!email) { + return; + } + + try { + const response = await fetch( + `${privateConfig.getRawPrivateConfig().server.fossorial_api}/api/v1/license-internal/enterprise/link-email-org`, + { + method: "POST", + headers: { + "api-key": + privateConfig.getRawPrivateConfig().server + .fossorial_api_key!, + "Content-Type": "application/json" + }, + body: JSON.stringify({ email, orgId }) + } + ); + + if (!response.ok && response.status !== 404) { + logger.error( + `Fossorial API returned ${response.status} when linking email ${email} to orgId ${orgId}: ${await response.text()}` + ); + } + } catch (error) { + logger.error( + `Error notifying Fossorial API of email/org link for orgId ${orgId}:`, + error + ); + } +} diff --git a/server/routers/org/createOrg.ts b/server/routers/org/createOrg.ts index a4efc991d..6abc589d6 100644 --- a/server/routers/org/createOrg.ts +++ b/server/routers/org/createOrg.ts @@ -25,7 +25,7 @@ import { fromError } from "zod-validation-error"; import { defaultRoleAllowedActions } from "../role"; import { OpenAPITags, registry } from "@server/openApi"; import { isValidCIDR } from "@server/lib/validators"; -import { createCustomer } from "#dynamic/lib/billing"; +import { createCustomer, linkEmailOrg } from "#dynamic/lib/billing"; import { usageService } from "@server/lib/billing/usageService"; import { LimitId, limitsService, freeLimitSet } from "@server/lib/billing"; import { build } from "@server/build"; @@ -425,6 +425,7 @@ export async function createOrg( customerId ); // Only 1 because we are creating the org } + await linkEmailOrg(orgId, req.user?.email); } if (numOrgs) {