[Additive] Vercel: 2 new response fields Vercel shipped two additive response fields to its API, permissions.schedulePreview and projects[].permissions.schedulePreview, alongside a set of new enum values that strict parsers and generated clients must handle. The new values include event names such as "ai-security-review", "firewall-conditional-bypass-updated", "integration-secret-rotated" and "vercel-agent-security-finding-created", plus "aws-oidc" for type, "org-admin-sync" for membership.joinedFrom.origin, "14cpu-28gb" for buildMachineType, and the permissions "read-write:ai-gateway-byok-credentials" and "read:ai-gateway-byok-credentials". Vercel labels the changes additive and says no action is needed, but notes they break exhaustive switches, strict parsers and generated client enums, and that fields such as transferRequest, v0 and elasticBuildMachine.memory now return undefined. Vercel https://driftwatch.et/apis/vercel 2 additive 2 new response fields - permissions.schedulePreview - projects .permissions.schedulePreview APIs https://driftwatch.et/providers / Vercel Breaking changes, deprecations and new fields in the Vercel API, as they ship. Producer-side tools call this additive. It breaks exhaustive switches, strict parsers and generated client enums. can now return "organization-team-dsync-update" switch response.name { // existing branches … // no branch for "organization-team-dsync-update" default: throw new Error "unexpected name" ; } can now return "aws-oidc" switch response.type { // existing branches … // no branch for "aws-oidc" default: throw new Error "unexpected type" ; } An unhandled branch in your error handling. can now return "ai-security-review", "firewall-conditional-bypass-updated", "integration-previous-secret-revoked", "integration-secret-rotated", "team-runtime-cache-updated", "vercel-agent-security-finding-created" switch response.name { // existing branches … // no branch for "ai-security-review" // no branch for "firewall-conditional-bypass-updated" // no branch for "integration-previous-secret-revoked" // no branch for "integration-secret-rotated" // no branch for "team-runtime-cache-updated" // no branch for "vercel-agent-security-finding-created" default: throw new Error "unexpected name" ; } switch response.source { // existing branches … // no branch for "project-overview-recommended-integrations" default: throw new Error "unexpected source" ; } Reads of this field return undefined, and the failure surfaces wherever that value is used rather than at the call. js // response.transferRequest is now undefined const transferRequest = response.transferRequest; No action needed. can now return "org-admin-sync" switch response.membership.joinedFrom.origin { // existing branches … // no branch for "org-admin-sync" default: throw new Error "unexpected origin" ; } can now return "team-data-cache-user-disabled-updated" switch response.replacedBy 0 { // existing branches … // no branch for "team-data-cache-user-disabled-updated" default: throw new Error "unexpected replacedBy" ; } can now return "connect-branding-updated" switch response.name { // existing branches … // no branch for "connect-branding-updated" default: throw new Error "unexpected name" ; } can now return "14cpu-28gb" switch response.resourceConfig.buildMachineType { // existing branches … // no branch for "14cpu-28gb" default: throw new Error "unexpected buildMachineType" ; } can now return "read-write:ai-gateway-byok-credentials", "read:ai-gateway-byok-credentials" switch response.payload.permissions 0 { // existing branches … // no branch for "read-write:ai-gateway-byok-credentials" // no branch for "read:ai-gateway-byok-credentials" default: throw new Error "unexpected permissions" ; } No action needed unless it is required. // response.projects 0 .resourceConfig.elasticBuildMachine.memory is now undefined const memory = response.projects 0 .resourceConfig.elasticBuildMachine.memory; // response.defaultResourceConfig.elasticBuildMachine.label is now undefined const label = response.defaultResourceConfig.elasticBuildMachine.label; // response.projects 0 .defaultResourceConfig.elasticBuildMachine.cores is now undefined const cores = response.projects 0 .defaultResourceConfig.elasticBuildMachine.cores; Dead branch, or an undocumented response you still receive. js // response.v0 is now undefined const v0 = response.v0; can now return "project-git-credential-attestation-created", "project-git-credential-attestation-deleted", "project-git-credential-grant-attestation-revoked", "project-git-credential-grant-attested" switch response.name { // existing branches … // no branch for "project-git-credential-attestation-created" // no branch for "project-git-credential-attestation-deleted" // no branch for "project-git-credential-grant-attestation-revoked" // no branch for "project-git-credential-grant-attested" default: throw new Error "unexpected name" ; } can now return "project" switch response.creator.type { // existing branches … // no branch for "project" default: throw new Error "unexpected type" ; } can now return "messageboard-project-channel-created", "messageboard-project-private-channel-created" switch response.name { // existing branches … // no branch for "messageboard-project-channel-created" // no branch for "messageboard-project-private-channel-created" default: throw new Error "unexpected name" ; } can now return "messageboard-private-project-granted", "messageboard-private-project-revoked", "messageboard-project-granted", "messageboard-project-revoked" switch response.name { // existing branches … // no branch for "messageboard-private-project-granted" // no branch for "messageboard-private-project-revoked" // no branch for "messageboard-project-granted" // no branch for "messageboard-project-revoked" default: throw new Error "unexpected name" ; } can now return "startup-terms-accepted" switch response.replacedBy 0 { // existing branches … // no branch for "startup-terms-accepted" default: throw new Error "unexpected replacedBy" ; } A relaxation. Existing payloads are unaffected. can now return "organization-sso-deleted" switch response.name { // existing branches … // no branch for "organization-sso-deleted" default: throw new Error "unexpected name" ; } js // response.resourceConfig.buildMachine.cores is now undefined const cores = response.resourceConfig.buildMachine.cores; switch response.config.resourceConfig.buildMachine.purchaseType { // existing branches … // no branch for "14cpu-28gb" default: throw new Error "unexpected purchaseType" ; } can now return "read-write:webhooks" switch response.payload.permissions 0 { // existing branches … // no branch for "read-write:webhooks" default: throw new Error "unexpected permissions" ; } js // response.daemons 0 .config.replicas is now undefined const replicas = response.daemons 0 .config.replicas; js // response.daemons 0 .config.configuredReplicas is now undefined const configuredReplicas = response.daemons 0 .config.configuredReplicas; js // response.projects 0 .permissions.messageboardSpace is now undefined const messageboardSpace = response.projects 0 .permissions.messageboardSpace; can now return "product" switch response.payload.budget.budgetItem.scope { // existing branches … // no branch for "product" default: throw new Error "unexpected scope" ; } can now return "messageboard-channel-created", "messageboard-channel-updated", "messageboard-private-channel-created", "messageboard-private-channel-updated" switch response.replacedBy 0 { // existing branches … // no branch for "messageboard-channel-created" // no branch for "messageboard-channel-updated" // no branch for "messageboard-private-channel-created" // no branch for "messageboard-private-channel-updated" default: throw new Error "unexpected replacedBy" ; } js // response.ownerId is now undefined const ownerId = response.ownerId; js // response.payload.spaceId is now undefined const spaceId = response.payload.spaceId; can now return "xaa-updated" switch response.name { // existing branches … // no branch for "xaa-updated" default: throw new Error "unexpected name" ; } js // response.daemons 0 .config.image.vhs is now undefined const vhs = response.daemons 0 .config.image.vhs; js // response.daemons 0 .replicas.items 0 .iroh is now undefined const iroh = response.daemons 0 .replicas.items 0 .iroh; can now return "use:github" switch response.payload.permissions 0 { // existing branches … // no branch for "use:github" default: throw new Error "unexpected permissions" ; } js // response.payload.data.reason is now undefined const reason = response.payload.data.reason; js // response.payload.data.planSlug is now undefined const planSlug = response.payload.data.planSlug; No error is raised. The value is ignored and your results change silently, which is the hardest class of break to notice. await client.post "/v2/sandboxes/sessions/{sessionId}/cmd", { // cmdId is now ignored, not rejected cmdId: value, } ; can now return "connect-cancel-mcp-event-subscription", "connect-create-mcp-event-subscription", "organization-name-update" switch response.type { // existing branches … // no branch for "connect-cancel-mcp-event-subscription" // no branch for "connect-create-mcp-event-subscription" // no branch for "organization-name-update" default: throw new Error "unexpected type" ; } can now return "read-write:access-group" switch response.payload.nextPermissions 0 { // existing branches … // no branch for "read-write:access-group" default: throw new Error "unexpected nextPermissions" ; } Producer-side tools call this non-breaking. For a consumer it is a null dereference on an unknown future date. js // response.payload.author may now be absent or null const author = response.payload.author ?? fallback; can now return "26.x" switch response.projects 0 .nodeVersion { // existing branches … // no branch for "26.x" default: throw new Error "unexpected nodeVersion" ; } js // response.result is now undefined const result = response.result; js // response.pagination is now undefined const pagination = response.pagination; can now return "firewall-conditional-bypass-created", "firewall-conditional-bypass-deleted" switch response.name { // existing branches … // no branch for "firewall-conditional-bypass-created" // no branch for "firewall-conditional-bypass-deleted" default: throw new Error "unexpected name" ; } No action needed unless you validate responses against a closed schema. can now return "response code" switch response.active.rulesets 0 .conditionGroup 0 .conditions 0 .type { // existing branches … // no branch for "response code" default: throw new Error "unexpected type" ; } can now return "read-write:project-members", "read:audit-log", "read:project-members" switch response.payload.permissions 0 { // existing branches … // no branch for "read-write:project-members" // no branch for "read:audit-log" // no branch for "read:project-members" default: throw new Error "unexpected permissions" ; } can now return "read-write:ai-gateway-budgets", "read:ai-gateway-budgets" switch response.payload.after.permissions 0 { // existing branches … // no branch for "read-write:ai-gateway-budgets" // no branch for "read:ai-gateway-budgets" default: throw new Error "unexpected permissions" ; } // response.services 0 .builder.config.daemon.replicas may now be absent or null const replicas = response.services 0 .builder.config.daemon.replicas ?? fallback; Usually ignored rather than rejected, so the call succeeds and does something subtly different. await client.post "/v9/projects/{idOrName}", { // protectionMode is now ignored, not rejected protectionMode: value, } ; can now return "admin-saml-sp-signing-key-created", "admin-saml-sp-signing-key-updated" switch response.name { // existing branches … // no branch for "admin-saml-sp-signing-key-created" // no branch for "admin-saml-sp-signing-key-updated" default: throw new Error "unexpected name" ; } can now return "organization-dsync-sync-start" switch response.name { // existing branches … // no branch for "organization-dsync-sync-start" default: throw new Error "unexpected name" ; } can now return "admin-saml-idp-material-deleted", "admin-saml-idp-material-set", "vercel-ci-repository-settings-updated" switch response.name { // existing branches … // no branch for "admin-saml-idp-material-deleted" // no branch for "admin-saml-idp-material-set" // no branch for "vercel-ci-repository-settings-updated" default: throw new Error "unexpected name" ; } can now return "stripe-api-key" switch response.type { // existing branches … // no branch for "stripe-api-key" default: throw new Error "unexpected type" ; } can now return "sandbox-drive-snapshot-created", "sandbox-drive-snapshot-deleted" switch response.name { // existing branches … // no branch for "sandbox-drive-snapshot-created" // no branch for "sandbox-drive-snapshot-deleted" default: throw new Error "unexpected name" ; } can now return "organization-dsync-delete" switch response.type { // existing branches … // no branch for "organization-dsync-delete" default: throw new Error "unexpected type" ; }