sso
SAML and OIDC single sign-on connections. 6 operations. Shapes are sketches of the declared schemas, bounded in depth — the authoritative document is linked from the index.
GET/orgs/{orgSlug}/sso/connections
Requires bearerAuth
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
orgSlugrequired | path | string | min length 1, max length 64 |
Response 200
{
connections: {
id: string
orgId: string
protocol: "SAML" | "OIDC"
enabled: boolean
enforced: boolean
defaultRole: string
attributeMapping: Record<string, unknown> | null
roleMapping: Record<string, unknown> | null
idpEntityId: string | null
idpSsoUrl: string | null
idpCertificateConfigured: boolean
idpCertificateAlternateCount: number
oidcIssuer: string | null
oidcClientId: string | null
oidcClientSecretConfigured: boolean
oidcScopes: string[]
createdAt: string
updatedAt: string
}[]
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 401 · `unauthorized` — no credential, or one that is expired, revoked or not valid for this resource. `mfa_required` when the credential is good but a second factor is owed.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 403 · `forbidden` — the credential is valid and its scopes or this principal’s membership do not reach this resource. Scopes are re-intersected with live memberships on every request, so this can appear for a token that worked yesterday.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 404 · `not_found` — no such resource, OR one this principal cannot see. The two are deliberately one answer: a 403 would confirm the existence of something whose identifier is guessable.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl https://api.bucker.io/orgs/{orgSlug}/sso/connections \
-H 'authorization: Bearer $BUCKER_TOKEN'DELETE/orgs/{orgSlug}/sso/connections/{protocol}
Requires bearerAuth
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
orgSlugrequired | path | string | min length 1, max length 64 |
protocolrequired | path | "SAML" | "OIDC" | one of "SAML" | "OIDC" |
Response 200
{
deleted: true
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 401 · `unauthorized` — no credential, or one that is expired, revoked or not valid for this resource. `mfa_required` when the credential is good but a second factor is owed.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 403 · `forbidden` — the credential is valid and its scopes or this principal’s membership do not reach this resource. Scopes are re-intersected with live memberships on every request, so this can appear for a token that worked yesterday.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 404 · `not_found` — no such resource, OR one this principal cannot see. The two are deliberately one answer: a 403 would confirm the existence of something whose identifier is guessable.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl -X DELETE https://api.bucker.io/orgs/{orgSlug}/sso/connections/{protocol} \
-H 'authorization: Bearer $BUCKER_TOKEN'PUT/orgs/{orgSlug}/sso/connections/{protocol}
Requires bearerAuth
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
orgSlugrequired | path | string | min length 1, max length 64 |
protocolrequired | path | "SAML" | "OIDC" | one of "SAML" | "OIDC" |
Request body (required) · application/json
{
enabled?: boolean
enforced?: boolean
defaultRole?: "VIEWER" | "BILLING" | "MEMBER" | "ADMIN"
attributeMapping?: Record<string, string | string[]> | null
roleMapping?: Record<string, string> | null
idpEntityId?: string | null
idpSsoUrl?: string (uri) | null
idpCertificate?: string | null
idpCertificateAlternates?: string[]
oidcIssuer?: string (uri) | null
oidcClientId?: string | null
oidcClientSecret?: string | null
oidcScopes?: string[]
}Response 200
{
id: string
orgId: string
protocol: "SAML" | "OIDC"
enabled: boolean
enforced: boolean
defaultRole: string
attributeMapping: Record<string, unknown> | null
roleMapping: Record<string, unknown> | null
idpEntityId: string | null
idpSsoUrl: string | null
idpCertificateConfigured: boolean
idpCertificateAlternateCount: number
oidcIssuer: string | null
oidcClientId: string | null
oidcClientSecretConfigured: boolean
oidcScopes: string[]
createdAt: string
updatedAt: string
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 401 · `unauthorized` — no credential, or one that is expired, revoked or not valid for this resource. `mfa_required` when the credential is good but a second factor is owed.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 403 · `forbidden` — the credential is valid and its scopes or this principal’s membership do not reach this resource. Scopes are re-intersected with live memberships on every request, so this can appear for a token that worked yesterday.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 404 · `not_found` — no such resource, OR one this principal cannot see. The two are deliberately one answer: a 403 would confirm the existence of something whose identifier is guessable.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl -X PUT https://api.bucker.io/orgs/{orgSlug}/sso/connections/{protocol} \
-H 'authorization: Bearer $BUCKER_TOKEN' \
-H 'content-type: application/json' \
-d '{ … }'POST/sso/handoff
No declared credential scheme
Reachable without a Bucker session token. Spends the one-time code the two legs above 302 to the dashboard with; the opaque 256-bit code in the body IS the credential, exactly as the refresh token is at /auth/refresh, and the session it buys does not exist until it is spent.
Request body (required) · application/json
{
code: string
}Response 200
{
orgId: string
role: string
provisioned: boolean
tokens: {
accessToken: string
refreshToken: string
expiresIn: number
tokenType: "Bearer"
}
user: {
id: string
email: string
name: string
avatarUrl: string | null
locale: string
theme: string
emailVerified: boolean
mfaEnabled: boolean
createdAt: string
}
next: string | null
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl -X POST https://api.bucker.io/sso/handoff \
-H 'content-type: application/json' \
-d '{ … }'GET/sso/oidc/{orgSlug}/callback
No declared credential scheme
Reachable without a Bucker session token. The OP redirects back with a code bound to our state.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
orgSlugrequired | path | string | min length 1, max length 64 |
format | query | "redirect" | "json" | default "redirect", one of "redirect" | "json" |
code | query | string | min length 1, max length 4096 |
state | query | string | min length 1, max length 512 |
error | query | string | max length 256 |
error_description | query | string | max length 1024 |
Response 200
{
user: {
id: string
email: string
name: string
}
orgId: string
role: string
provisioned: boolean
relayState: string | null
tokens: {
accessToken: string
refreshToken: string
expiresIn: number
tokenType: "Bearer"
}
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 404 · `not_found` — no such resource, OR one this principal cannot see. The two are deliberately one answer: a 403 would confirm the existence of something whose identifier is guessable.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl https://api.bucker.io/sso/oidc/{orgSlug}/callbackPOST/sso/saml/{orgSlug}/acs
No declared credential scheme
Reachable without a Bucker session token. The IdP posts the signed assertion here; the signature is the authentication.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
orgSlugrequired | path | string | min length 1, max length 64 |
format | query | "redirect" | "json" | default "redirect", one of "redirect" | "json" |
Request body (required) · application/json
{
SAMLResponse: string
RelayState?: string
}Response 200
{
user: {
id: string
email: string
name: string
}
orgId: string
role: string
provisioned: boolean
relayState: string | null
tokens: {
accessToken: string
refreshToken: string
expiresIn: number
tokenType: "Bearer"
}
}Response 400 · `bad_request` — the path, query or body failed validation. `details` carries the Zod issues, one per offending field.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 404 · `not_found` — no such resource, OR one this principal cannot see. The two are deliberately one answer: a 403 would confirm the existence of something whose identifier is guessable.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 429 · `rate_limited` or `quota_exceeded` — over a ceiling. `Retry-After` says when to come back, and `x-ratelimit-limit` / `-remaining` / `-reset` describe the bucket.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Response 500 · `internal_error` — an unhandled failure on this side. The message is always generic; `requestId` is the part worth quoting.
{
error: {
code: "bad_request" | "conflict" | "forbidden" | "internal_error" | "mfa_required" | "not_found" | "payload_too_large" | "quota_exceeded" | … 6 more
message: string
details?: unknown
requestId?: string
}
}Request
curl -X POST https://api.bucker.io/sso/saml/{orgSlug}/acs \
-H 'content-type: application/json' \
-d '{ … }'