From c34bf47ebbeb21a8e09537be1e133b6384958b58 Mon Sep 17 00:00:00 2001 From: Mike Wickett Date: Tue, 21 Apr 2026 08:05:05 -0400 Subject: [PATCH 1/2] feat(plapi): stamp from_source=cli on authenticated app creation --- .changeset/cli-attribution-stamp.md | 5 +++++ packages/cli-core/src/lib/plapi.test.ts | 2 +- packages/cli-core/src/lib/plapi.ts | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/cli-attribution-stamp.md diff --git a/.changeset/cli-attribution-stamp.md b/.changeset/cli-attribution-stamp.md new file mode 100644 index 00000000..bd446e99 --- /dev/null +++ b/.changeset/cli-attribution-stamp.md @@ -0,0 +1,5 @@ +--- +"clerk": minor +--- + +Stamp authenticated CLI app creation with `from_source=cli` so apps created through Clerk CLI flows are attributable in Clerk's analytics. The value is set on the PLAPI request body and persists to `applications.from_source`. Requires matching PLAPI support to be deployed server-side. diff --git a/packages/cli-core/src/lib/plapi.test.ts b/packages/cli-core/src/lib/plapi.test.ts index 0b473eb9..94c70e86 100644 --- a/packages/cli-core/src/lib/plapi.test.ts +++ b/packages/cli-core/src/lib/plapi.test.ts @@ -305,7 +305,7 @@ describe("plapi", () => { await createApplication("My App"); expect(capturedMethod).toBe("POST"); expect(capturedUrl).toBe("https://api.clerk.com/v1/platform/applications"); - expect(JSON.parse(capturedBody)).toEqual({ name: "My App" }); + expect(JSON.parse(capturedBody)).toEqual({ name: "My App", from_source: "cli" }); }); test("sends Content-Type and Authorization headers", async () => { diff --git a/packages/cli-core/src/lib/plapi.ts b/packages/cli-core/src/lib/plapi.ts index 4e2fa331..ea8a4ce1 100644 --- a/packages/cli-core/src/lib/plapi.ts +++ b/packages/cli-core/src/lib/plapi.ts @@ -9,6 +9,19 @@ import { CliError, PlapiError, ERROR_CODE } from "./errors.ts"; import { loggedFetch } from "./fetch.ts"; import { log } from "./log.ts"; +/** + * Canonical attribution marker written to `applications.from_source` when the + * CLI creates an application through PLAPI. Surfaces in BigQuery via + * `dim_applications.from_source` for growth analytics. Do not change without + * coordinating with the growth-data team — the value is consumed by dbt + * models and dashboards downstream. + */ +const CLI_FROM_SOURCE = "cli"; + +/** + * Validate that a key has the expected prefix and suggest the correct key type + * if the user mixed them up. + */ export function validateKeyPrefix(key: string, expected: "ak_" | "sk_"): void { if (key.startsWith(expected)) return; @@ -167,7 +180,9 @@ export const patchInstanceConfig = ( export async function createApplication(name: string): Promise { const url = new URL("/v1/platform/applications", getPlapiBaseUrl()); - const response = await plapiFetch("POST", url, { body: JSON.stringify({ name }) }); + const response = await plapiFetch("POST", url, { + body: JSON.stringify({ name, from_source: CLI_FROM_SOURCE }), + }); return response.json() as Promise; } From cf7db71d27ebae3af45d68576d4c71fcd4e0e580 Mon Sep 17 00:00:00 2001 From: Mike Wickett Date: Tue, 21 Apr 2026 08:37:58 -0400 Subject: [PATCH 2/2] style(plapi): em-dash to regular dash per reviewer nit --- packages/cli-core/src/lib/plapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-core/src/lib/plapi.ts b/packages/cli-core/src/lib/plapi.ts index ea8a4ce1..6e62847e 100644 --- a/packages/cli-core/src/lib/plapi.ts +++ b/packages/cli-core/src/lib/plapi.ts @@ -13,7 +13,7 @@ import { log } from "./log.ts"; * Canonical attribution marker written to `applications.from_source` when the * CLI creates an application through PLAPI. Surfaces in BigQuery via * `dim_applications.from_source` for growth analytics. Do not change without - * coordinating with the growth-data team — the value is consumed by dbt + * coordinating with the growth-data team - the value is consumed by dbt * models and dashboards downstream. */ const CLI_FROM_SOURCE = "cli";