---
title: Handling Integrations
description: Learn how to handle integration requests and follow-up script permissions in the v0 API
product: v0 API
type: guide
related:
  - /docs/api/v2/guides/environment-variables
  - /docs/api/v2/reference/mcp-servers/create-mcp-server
  - /docs/api/v2/reference/messages/resolve-task
---

# Handling Integrations



Learn how to handle integration requests when a v0 chat pauses and needs input from your app. The short version is:

1. Prompt the agent.
2. Inspect the latest assistant message and read the chat's `vercelProjectId`.
3. Install the integration with the Vercel API.
4. Confirm the install with `POST /v2/chats/{chatId}/messages/resolve`.
5. Handle script permissions if the agent asks for them next.

This guide focuses on the integration flow. For the full task schema, see [Resolve Task](/docs/api/v2/reference/messages/resolve-task).

## 1. Prompt the agent

Start or continue a chat with a request that depends on an integration.

For example:

* "Build a waiting list app with Neon."
* "Create a dashboard that uses Supabase auth."

If the agent can continue without extra setup, it will. If it needs an integration, it will stop and ask your app to handle it.

## 2. Inspect the latest assistant message

When a chat is blocked on integration setup, inspect the latest assistant message first. How you access it depends on the response mode:

* **Synchronous**: The request returns the completed assistant message directly.
* **Asynchronous**: The request returns a `messageId`. Poll `GET /v2/chats/{chatId}/messages/{messageId}` until `finishReason` is no longer `null`.
* **Streaming**: Consume `result.stream` for updates, then inspect `result.final.parts` for the completed message parts.

An integration request surfaces as an `agent-action` part in the message's `parts` array with `name: "get_or_request_integration"`. Its `data.requestedIntegrations` lists the integration names to install (for example, `["Neon"]`), and `data.requestedMcpPresets` lists any MCP presets. You pass these values back in step 4.

```typescript
import { v0 } from 'v0'

const message = await v0.messages.send({
  chatId: 'chat_abc123',
  message: 'Build a waiting list app with Neon.',
})

const integrationRequest = message.parts.find(
  (part) =>
    part.type === 'agent-action' &&
    part.name === 'get_or_request_integration',
)
```

Use the latest blocked assistant message only. If you try to resolve an older task after the chat has moved on, `resolve-task` returns `409 Conflict`.

## 3. Install the integration with the Vercel API

Once you know which integration the assistant is asking for, install or connect it in Vercel.

Use the chat's `vercelProjectId` for the project-scoped Vercel API calls in this step. `vercelProjectId` is the linked Vercel project ID. Do not use `projectId` here. `projectId` is the separate v0 project ID, and it is deprecated in the chat response.

```typescript
import { v0 } from 'v0'

const chatResult = await v0.chats.get({
  chatId: 'chat_abc123',
})

if (chatResult.error) throw new Error(chatResult.error.message)

const chat = chatResult.data
let { vercelProjectId } = chat

if (!vercelProjectId) {
  const projectResult = await v0.chats.createVercelProject({
    chatId: chat.id,
  })

  if (projectResult.error) throw new Error(projectResult.error.message)
  vercelProjectId = projectResult.data.vercelProjectId
}
```

This step happens outside the v0 API. The exact Vercel API calls depend on your integration flow, but these docs are the relevant starting points:

* [Create Integration Store Free and Paid Plans](https://vercel.com/docs/rest-api/integrations/create-integration-store-free-and-paid-plans)
* [Connect Integration Resource to Project](https://vercel.com/docs/rest-api/integrations/connect-integration-resource-to-project)

When you call the Vercel endpoint that connects a resource to a project, pass `vercelProjectId` from the chat.

After the integration is actually connected, return to the v0 chat and confirm it with `resolve-task`.

## 4. Confirm the install with `resolve-task`

Use `task.type: "confirmed-steps"` after the integration is installed. Pass the integration names exactly as the assistant requested them, such as `Neon` or `Supabase`.

```typescript
import { v0 } from 'v0'

const result = await v0.messages.resolve({
  chatId: 'chat_abc123',
  task: {
    type: 'confirmed-steps',
    connectedIntegrationNames: ['Neon'],
  },
})

if (result.error) throw new Error(result.error.message)
```

If you are rejecting the integration request instead of approving it, pass an empty array:

```json
{
  "task": {
    "type": "confirmed-steps",
    "connectedIntegrationNames": []
  }
}
```

You can also confirm other setup work with the same task type, including MCP presets, scripts, and environment variables.

## 5. Handle script permissions if needed

After the integration is connected, the assistant may ask for permission to run follow-up scripts, such as database setup or migrations.

When that happens, inspect the latest assistant message again. The pending action surfaces as a `tool-call` part in the message's `parts` array. While the agent is waiting for your approval, that part includes a `suggestedPermissions` array.

To approve the request, call `resolve` with `task.type: "confirmed-permissions"` and pass the `suggestedPermissions` objects back unchanged as `task.permissions`.

The submitted permissions must match the ones currently pending on the latest blocked assistant message, or `resolve` returns `409 Conflict`.

```typescript
const permissionRequest = message.parts.find(
  (part) => part.type === 'tool-call' && part.suggestedPermissions?.length,
)

if (
  permissionRequest?.type === 'tool-call' &&
  permissionRequest.suggestedPermissions
) {
  await v0.messages.resolve({
    chatId: 'chat_abc123',
    task: {
      type: 'confirmed-permissions',
      permissions: permissionRequest.suggestedPermissions,
    },
  })
}
```

To reject the request, ignore the permission request and send any other follow-up message.

## Example Flow

Here is the full flow in plain English:

1. Your app prompts v0 to build something that needs Neon.
2. The assistant stops and asks for the Neon integration, surfaced as a `get_or_request_integration` agent-action part.
3. Your backend reads `vercelProjectId` from `GET /v2/chats/{chatId}` and uses that value in the Vercel API calls that connect Neon.
4. Your backend calls `POST /v2/chats/{chatId}/messages/resolve` with `connectedIntegrationNames: ["Neon"]`.
5. The assistant resumes. If it needs to run a migration script, it stops again with a `tool-call` part that carries `suggestedPermissions`.
6. Your backend passes those `suggestedPermissions` back in a `confirmed-permissions` task to approve.

That is the complete pattern for handling integrations in the v0 API.


---

For a semantic overview of all documentation, see [/docs/sitemap.md](/docs/sitemap.md)

For an index of all available documentation, see [/docs/llms.txt](/docs/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/docs/agents.md](/docs/agents.md)