cd /news/developer-tools/additive-vercel-2-new-response-field… · home › topics › developer-tools › article
[ARTICLE · art-162337] src=driftwatch.et ↗ pub= topic=developer-tools verified=true sentiment=· neutral

[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.

read7 min views1 publishedNov 2, 2026
[Additive] Vercel: 2 new response fields
Image: Driftwatch (auto-discovered)

Vercel2 additive

2 new response fields #

  • permissions.schedulePreview
  • projects[].permissions.schedulePreview

APIs / 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.

// 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.

// 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.

// 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");
}
── more in #developer-tools 4 stories · sorted by recency
── more on @vercel 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/additive-vercel-2-ne…] indexed:0 read:7min 2026-11-02 · —