This guide focuses on the code you are most likely to change when upgrading from v5 to v6 in this branch.
v6 is still recognizably the WorkOS Python SDK, but it moves onto a generated client and runtime. The highest-friction changes are import path updates, the portal to admin_portal rename, the removal of fga, the shift away from Pydantic model helpers, and the new error and retry behavior.
- Upgrade to Python 3.10+.
- Replace any
workos.clientorworkos.async_clientimports with top-level imports fromworkos. - Rename
client.portaltoclient.admin_portal. - Remove any
client.fgausage before upgrading. - Replace Pydantic-specific model code such as
model_validate()andmodel_dump(). - Review exception handling, pagination assumptions, and retry-sensitive call sites.
v5
[project]
requires-python = ">=3.8"v6
[project]
requires-python = ">=3.10"Affected users: Any application, worker, CI job, or deploy target still pinned to Python 3.8 or 3.9.
Migration: Upgrade your runtime before taking the SDK upgrade.
The client class names are unchanged, but the old module paths are gone.
v5
from workos.client import WorkOSClient
from workos.async_client import AsyncWorkOSClientv6
from workos import WorkOSClient, AsyncWorkOSClientAffected users: Anyone importing from workos.client or workos.async_client.
Migration: Move client imports to from workos import WorkOSClient, AsyncWorkOSClient.
This is the most visible service rename in v6. The generate_link argument also changed from organization_id to organization.
v5
link = client.portal.generate_link(
organization_id="org_123",
intent="sso",
)v6
link = client.admin_portal.generate_link(
organization="org_123",
intent="sso",
)Affected users: Anyone generating Admin Portal links.
Migration: Rename client.portal to client.admin_portal and update organization_id= to organization=.
There is no client.fga accessor in v6.
v5
fga = client.fgav6
# No v6 replacement is available in this branch.Affected users: Any integration still using the FGA surface.
Migration: Keep that integration on v5 for now, or split the FGA migration from the v6 SDK upgrade.
Generated models now use from_dict() and to_dict() instead of Pydantic APIs.
v5
from workos.types.audit_logs.audit_log_event import AuditLogEvent
event = AuditLogEvent.model_validate(payload)
body = event.model_dump()v6
from workos.audit_logs.models import AuditLogEvent
event = AuditLogEvent.from_dict(payload)
body = event.to_dict()Affected users: Anyone calling model_validate(), model_dump(), or relying on Pydantic-specific behavior.
Migration: Replace Pydantic helpers with from_dict() and to_dict(), and remove any dependence on Pydantic validators or BaseModel APIs.
The old *Exception naming is replaced with *Error, and the runtime now exposes more structured SDK-native errors.
v5
from workos.exceptions import NotFoundException
try:
client.organizations.get_organization("org_123")
except NotFoundException:
...v6
from workos import NotFoundError
try:
client.organizations.get_organization("org_123")
except NotFoundError as exc:
request_id = exc.request_id
status_code = exc.status_codeRepresentative renames:
BadRequestException->BadRequestErrorAuthenticationException->AuthenticationErrorAuthorizationException->AuthorizationErrorNotFoundException->NotFoundErrorConflictException->ConflictErrorServerException->ServerError
v6 also exposes runtime and auth-flow specific errors such as:
ConfigurationErrorUnprocessableEntityErrorRateLimitExceededErrorWorkOSConnectionErrorWorkOSTimeoutErrorEmailVerificationRequiredErrorMfaEnrollmentErrorMfaChallengeErrorOrganizationSelectionRequiredErrorSsoRequiredError
Affected users: Anyone using try/except with SDK exceptions or inspecting exception attributes.
Migration: Rename caught exception classes, update imports, and review any code that depends on old exception names or attributes.
List endpoints now return typed page wrappers with cursor metadata and built-in auto-pagination.
v6
page = client.organizations.list_organizations()
for organization in page:
print(organization.id)
assert page.before is None or isinstance(page.before, str)
assert page.after is None or isinstance(page.after, str)v6 async
page = await async_client.organizations.list_organizations()
items = [organization async for organization in page]Affected users: Any code that expected a handwritten list wrapper or manually handled pagination state differently.
Migration: Update pagination code to work with SyncPage or AsyncPage, and use page.data, page.before, page.after, or iteration over the page as needed.
The generated runtime retries retryable failures by default, including 429 and common 5xx responses.
v6
from workos import WorkOSClient
client = WorkOSClient(api_key="sk_test_123", max_retries=0)Per-request overrides are available through request_options.
from workos import WorkOSClient
client = WorkOSClient(api_key="sk_test_123")
client.organizations.list_organizations(
request_options={
"timeout": 5,
"max_retries": 0,
}
)Affected users: Latency-sensitive code paths, fail-fast integrations, and any callers that assumed immediate failure after a single request attempt.
Migration: Review retry-sensitive call sites and set max_retries=0 at the client or request level where fail-fast behavior is required.
v6 accepts either an API key or a client ID at client construction time.
v5
from workos import WorkOSClient
client = WorkOSClient(api_key="sk_test_123", client_id="client_123")v6
from workos import WorkOSClient
server_client = WorkOSClient(api_key="sk_test_123")
public_client = WorkOSClient(client_id="client_123")
hybrid_client = WorkOSClient(api_key="sk_test_123", client_id="client_123")Operations that require a missing credential now raise ConfigurationError when called.
Affected users: Code that relied on constructor-time validation to prove both credentials were present for all later operations.
Migration: Keep passing both values if that matches your app today, and audit flows that require api_key or client_id so missing-config errors do not surprise you at request time.
v6 prefers resource-local model imports such as workos.organizations.models and shared types in workos.common.models.
Package-level compatibility imports under workos.types.<resource> still exist in this branch. The bigger break is that old per-model module paths are no longer the preferred shape.
v5
from workos.types.organizations.organization import Organization
from workos.types.portal.portal_link_intent import PortalLinkIntentv6
from workos.organizations.models import Organization
from workos.common.models import GenerateLinkIntentTemporary compatibility still works for package-level imports:
from workos.types.organizations import OrganizationAffected users: Anyone importing individual model modules from the old workos.types.* tree.
Migration: Prefer workos.<resource>.models and workos.common.models for new code. If you need a lower-friction rollout, package-level workos.types.<resource> imports can bridge part of the migration in this branch.
WorkOSClientandAsyncWorkOSClientremain the top-level client names.- Most familiar service namespaces remain available, including
api_keys,audit_logs,authorization,connect,directory_sync,events,organization_domains,organizations,passwordless,pipes,sso,user_management,webhooks,widgets, andvault. client.mfastill works as an alias forclient.multi_factor_auth.- High-value helpers remain available, including
client.user_management.load_sealed_session(...),client.user_management.authenticate_with_password(...),client.user_management.get_authorization_url_with_pkce(...), andclient.sso.get_authorization_url_with_pkce(...). - Client configuration is still instance-scoped.
- Per-request options are supported and include
extra_headers,timeout,max_retries,base_url, andidempotency_key. - The runtime raises SDK-native errors instead of leaking raw
httpxexceptions as the primary public contract. - Retry handling honors
Retry-Afterwhen present. - POST requests automatically receive an idempotency key when one is not provided.
- Auto-pagination is wired and fetches subsequent pages.
- Upgrade Python to 3.10+ in local development, CI, and production.
- Replace
workos.clientandworkos.async_clientimports with top-level imports fromworkos. - Rename
client.portalusages toclient.admin_portal. - Find and remove any
client.fgausage. - Replace
model_validate()andmodel_dump()withfrom_dict()andto_dict(). - Update exception imports and any code that catches or inspects SDK errors.
- Audit pagination code that depends on the old list wrapper shape.
- Review retry-sensitive call sites and set
max_retries=0where required. - Migrate old model imports toward
workos.<resource>.modelsandworkos.common.models. - Run sync and async integration tests and look for import errors, attribute errors, serialization mismatches, and changed retry behavior.
rg 'workos\.client|workos\.async_client|client\.portal|client\.fga|model_dump|model_validate|Exception|workos\.types'- Python runtime is 3.10+.
- Client imports no longer use
workos.clientorworkos.async_client. client.portalusages are renamed toclient.admin_portal.client.fgausage is removed or isolated from the v6 upgrade.- Pydantic-only model helpers are gone.
- Exception imports use v6
*Errornames. - Retry behavior has been reviewed explicitly.
- Pagination code has been updated where needed.
- Model imports are moving toward
workos.<resource>.modelsandworkos.common.models. - Sync and async integration tests pass.