Skip to main content

Upgrade to API version 2026-05-12

Version 2026-05-12 of Clerk's Frontend and Backend APIs removes metadata fields from the general-purpose user and Organization update endpoints. Metadata must now be set through the dedicated metadata endpoints: the PATCH endpoints deep-merge the provided values, while the PUT endpoints replace the provided metadata fields in full.

To use this new API version, refer to the versioning guide. This guide documents all updates at the API level. Since implementation details may differ between SDKs, it will help you identify which parts of your SDK usage may require additional review in the documentation, and assist consumers using unofficial or custom API clients in managing the upgrade.

Backend endpoint changes

Users

PATCH /v1/users/{user_id} no longer accepts the following fields in the request body:

  • public_metadata
  • private_metadata
  • unsafe_metadata

To update user metadata, use one of the dedicated endpoints below:

EndpointSemantics
PATCH /v1/users/{user_id}/metadataDeep-merges the provided values into the existing metadata. Any key set to null is removed.
PUT /v1/users/{user_id}/metadataReplaces each provided top-level metadata field in full — no merging at any level. Top-level fields omitted from the request body are left untouched. Send {} to clear a field, or null to store a JSON null value.

Choose PATCH when you want to update specific keys without affecting others, and PUT when you want to overwrite an entire metadata field.

If you are using a Clerk SDK, use the updateUserMetadata() method (which wraps PATCH) or the replaceUserMetadata() method (which wraps PUT) instead of passing metadata fields to updateUser().

await clerkClient.users.updateUser(userId, {
  publicMetadata: {
    role: 'admin',
  },
})
await clerkClient.users.updateUserMetadata(userId, {
  publicMetadata: {
    role: 'admin',
  },
})

await clerkClient.users.replaceUserMetadata(userId, {
  publicMetadata: {
    role: 'admin',
  },
})

Organizations

PATCH /v1/organizations/{organization_id} no longer accepts the following fields in the request body:

  • public_metadata
  • private_metadata

To update Organization metadata, use one of the dedicated endpoints below:

EndpointSemantics
PATCH /v1/organizations/{organization_id}/metadataDeep-merges the provided values into the existing metadata. Any key set to null is removed.
PUT /v1/organizations/{organization_id}/metadataReplaces each provided top-level metadata field in full — no merging at any level. Top-level fields omitted from the request body are left untouched. Send {} to clear a field, or null to store a JSON null value.

Choose PATCH when you want to update specific keys without affecting others, and PUT when you want to overwrite an entire metadata field.

If you are using a Clerk SDK, use the updateOrganizationMetadata() method (which wraps PATCH) or the replaceOrganizationMetadata() method (which wraps PUT) instead of passing metadata fields to updateOrganization().

await clerkClient.organizations.updateOrganization(organizationId, {
  publicMetadata: {
    tier: 'enterprise',
  },
})
await clerkClient.organizations.updateOrganizationMetadata(organizationId, {
  publicMetadata: {
    tier: 'enterprise',
  },
})

await clerkClient.organizations.replaceOrganizationMetadata(organizationId, {
  publicMetadata: {
    tier: 'enterprise',
  },
})

Frontend endpoint changes

PATCH /v1/me no longer accepts the unsafe_metadata field in the request body.

To update unsafe metadata from the frontend, use the dedicated endpoint PATCH /v1/me/metadata instead. This endpoint deep-merges the provided value with the existing unsafeMetadata, and any key set to null is removed.

If you are using a Clerk SDK, use the updateMetadata() method on the User object instead of passing unsafeMetadata to update().

await user.update({
  unsafeMetadata: {
    ...user.unsafeMetadata,
    theme: 'dark',
  },
})
await user.updateMetadata({
  unsafeMetadata: { theme: 'dark' },
})

Feedback

What did you think of this content?

Last updated on