Skip to content

Upload a custom extension

POST
/extensions
curl --request POST \
  --url http://localhost:8000/extensions \
  --header 'API-Key: <API-Key>' \
  --header 'API-Version: 2026-06-01.beta' \
  --header 'Content-Type: multipart/form-data' \
  --form jar=@file \
  --form 'metadata={ "name": "example", "description": "example", "keycloak_version": "example", "version": "example", "parameter_type": "env", "parameters": [ { "key": "example", "label": "example", "type": "text", "required": true, "default_value": "example", "options": [ { "value": "example", "label": "example" } ], "is_sensitive": true } ], "repository_url": "https://example.com", "icon_url": "https://example.com" }'

Uploads a new custom extension JAR to the workspace. The JAR is asynchronously scanned for malware; poll the returned extension’s scan_status until it reaches ready before installing on a cluster.

Maximum body size is 150 MB.

Required scope: extensions:write

API-Version
required
string
Allowed values: 2026-06-01.beta
Media typemultipart/form-data
object
jar
required

JAR file containing the Keycloak extension. Content type must be application/java-archive.

string format: binary
metadata
required

Extension metadata and parameter schema.

object
name
required
string
>= 1 characters <= 200 characters
description
string
<= 2000 characters
keycloak_version
required

Keycloak major version this JAR targets (e.g. "26").

string
>= 1 characters <= 10 characters
version

Semantic version string (e.g. "1.0.0"). Defaults to 1.0.0.

string
<= 50 characters
parameter_type
string
Allowed values: env cli realm_attributes
parameters
Array<object>
object
key
required
string
>= 1 characters <= 100 characters
label
required
string
>= 1 characters <= 200 characters
type
required
string
Allowed values: text dropdown checkbox number password
required
required
boolean
default_value
string
options
Array<object>
object
value
required
string
label
required
string
is_sensitive
boolean
repository_url
string format: uri
icon_url
string format: uri

The request has succeeded and a new resource has been created as a result.

Media typeapplication/json
object
id
required
string format: uuid
name
required
string
>= 1 characters <= 200 characters
display_name

Friendly name shown in place of name when set. name never changes once an extension is catalogued; display_name lets the shown label change independently. Absent or null when the extension has none, in which case clients should fall back to name.

string
nullable <= 200 characters
description
required
string
nullable
source
required
string
Allowed values: platform custom
visibility

Set for platform extensions only: private marks an early-access extension your workspace has been granted. Absent for custom extensions.

string
Allowed values: public private
version
required

Active version of the extension. For platform extensions this is the newest release across its supported Keycloak versions; the version a given cluster gets is available_version on its cluster extension. For custom extensions it is the uploader-supplied version.

string
previous_versions
required

Previously published versions, ordered from oldest to newest.

Array<object>
object
version
required
string
created_at
required
string format: date-time
keycloak_versions
required

Supported Keycloak major versions (e.g. ["25", "26"]).

Array<string>
parameter_type
required
string
Allowed values: env cli realm_attributes
parameters
required
Array<object>
object
key
required

Unique parameter identifier within the extension.

string
>= 1 characters <= 100 characters
label
required
string
>= 1 characters <= 200 characters
type
required
string
Allowed values: text dropdown checkbox number password
required
required
boolean
default_value
required
string
nullable
options
required

Available choices. Only applicable when type is dropdown.

Array<object>
object
value
required
string
label
required
string
is_sensitive
required

When true, the parameter value is write-only and omitted from read responses.

boolean
repository_url
required
string format: uri
nullable
icon_url
required
string format: uri
nullable
documentation_url
required
string format: uri
nullable
quick_start_steps
required
string
nullable
usage_notes
required
string
nullable
scan_status
required

Malware scan result. Only set for custom extensions.

string
Allowed values: scanning ready rejected failed
scan_message
required

Human-readable scan result. Present when scan_status is rejected (names the detected signature) or failed (says the scan could not complete).

string
nullable
original_jar_name
required

Original JAR filename provided at upload time. Only set for custom extensions.

string
nullable
file_size_bytes
required

JAR file size in bytes. Only set for custom extensions.

integer
nullable
uploaded_at
required

When the extension was first uploaded. Only set for custom extensions.

string format: date-time
nullable
created_at
required
string format: date-time
updated_at
required
string format: date-time

Example

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "Social Login Bundle",
  "description": "Adds social login providers for Google, GitHub, and Microsoft.",
  "source": "platform",
  "version": "3.1.0",
  "previous_versions": [],
  "keycloak_versions": [
    "25",
    "26"
  ],
  "parameter_type": "env",
  "parameters": [],
  "repository_url": null,
  "icon_url": null,
  "documentation_url": null,
  "quick_start_steps": null,
  "usage_notes": null,
  "scan_status": null,
  "scan_message": null,
  "original_jar_name": null,
  "file_size_bytes": null,
  "uploaded_at": "2025-01-15T10:00:00Z",
  "created_at": "2025-01-15T10:00:00Z",
  "updated_at": "2025-03-20T14:30:00Z"
}

The server could not understand the request due to invalid syntax.

Media typeapplication/problem+json

RFC 9457 Problem Details object.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com"
}

Access is unauthorized.

Media typeapplication/problem+json

RFC 9457 Problem Details object.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com"
}

Client error

Media typeapplication/problem+json

Returned when a workspace plan quota would be exceeded. required_plan indicates the minimum plan needed to complete the request.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri
current_plan
required
string
required_plan
required
string
code

Machine-readable identifier of the quota that was hit, so a client can tell quotas apart without parsing detail. Known values include cluster_limit (the workspace’s total cluster allowance), cluster_size_quota (the allowance for the requested cluster size) and cluster_size (the requested size is not offered on the plan at all). New values may be added.

string
current_usage

How many of the resource the workspace currently has.

integer
current_limit

Maximum allowed by the current plan. 0 means the plan does not include the resource at all.

integer

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com",
  "current_plan": "example",
  "required_plan": "example",
  "code": "example",
  "current_usage": 1,
  "current_limit": 1
}

Client error

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri
errors
required
Array<object>
>= 1 items
object
field
required
string
detail
required
string
code
string
value

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com",
  "errors": [
    {
      "field": "example",
      "detail": "example",
      "code": "example",
      "value": "example"
    }
  ]
}

Client error

Media typeapplication/problem+json

RFC 9457 Problem Details object.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com"
}
Retry-After
integer
RateLimit-Limit
integer
RateLimit-Remaining
integer
RateLimit-Reset
integer
X-RateLimit-Limit-Second
integer
X-RateLimit-Remaining-Second
integer
X-RateLimit-Limit-Minute
integer
X-RateLimit-Remaining-Minute
integer
X-RateLimit-Limit-Hour
integer
X-RateLimit-Remaining-Hour
integer
X-RateLimit-Limit-Day
integer
X-RateLimit-Remaining-Day
integer

Server error

Media typeapplication/problem+json

RFC 9457 Problem Details object.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com"
}

Server error

Media typeapplication/problem+json

RFC 9457 Problem Details object.

object
type
required
string format: uri
title
required
string
status
required
integer
detail
required
string
instance
string format: uri

Example generated

{
  "type": "https://example.com",
  "title": "example",
  "status": 1,
  "detail": "example",
  "instance": "https://example.com"
}