Skip to content

Overview

SDK keys within a resolved organization + project + environment — one level deeper than EnvironmentsController. Every action resolves {project} (key-or-guid, scoped to the resolved org, with the service-token project allowlist forwarded) then {env} (key-or-guid, scoped to the resolved project) via IPublicApiTenantResolver, mirroring FeatureFlagsController’s resolve-then-dispatch shape. Unlike {project}/{env}, {sdkKey} is guid-only — SDK keys have no key/slug of their own — resolved via ResolveSdkKeyIdAsync, which throws the same not-found error for a non-guid segment as a genuinely missing key. Writes (create/update/revoke) require at least Member (RequireRole); a Viewer attempting one gets a 403 forbidden envelope.

Type is a bare string on the wire; Create parses it to SdkKeyType against a NAME allowlist (Enum.TryParse + Enum.GetNames().Contains(...)) rather than a bare Enum.TryParse/Enum.IsDefined pair — the latter would silently accept a numeric string (e.g. "0") and resolve it to the first enum member. An unrecognized value throws the custom ValidationException BEFORE the environment is resolved or any command is dispatched, mapped to a 400 validation_failed envelope by PublicApiExceptionFilterAttribute — same pattern as MapConditions’s operator parse. The plaintext key returned by CreateSdkKeyResult is a one-time value — it is never recoverable afterward, so unlike Create’s re-fetch-after-write pattern, Create builds its response directly from the command result rather than dispatching a follow-up query. List and Get return PublicSdkKeyResponse, which carries only LastFourCharacters — never the plaintext.