# Update a deal

`PATCH https://api.versionseven.ai/v1/crm/deals/{deal_id}`

Updates the fields you send and leaves the rest unchanged.

> **Note:** `custom_fields` sent here is stored in the deal's `metadata`.

- Required scope: `crm:write`

## Request

**cURL**

```bash
curl -X PATCH "https://api.versionseven.ai/v1/crm/deals/a47d043f-fc68-49de-bf05-8861f91f61e8" \
  -H "Authorization: Bearer $VICTORIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "actual_close_date": "2024-03-15T00:00:00+00:00",
  "custom_fields": {
    "priority": "high"
  },
  "expected_close_date": "2024-03-31T00:00:00+00:00",
  "name": "Acme Corp - Enterprise License",
  "notes": "Contract under legal review",
  "owner_id": "f4a5b6c7-d8e9-0123-f012-456789012345",
  "probability": 75,
  "stage_id": "d2e3f4a5-b6c7-8901-def0-234567890123",
  "value": 75000
}'
```

**Node.js**

```javascript
const response = await fetch("https://api.versionseven.ai/v1/crm/deals/a47d043f-fc68-49de-bf05-8861f91f61e8", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.VICTORIA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "actual_close_date": "2024-03-15T00:00:00+00:00",
    "custom_fields": {
      "priority": "high"
    },
    "expected_close_date": "2024-03-31T00:00:00+00:00",
    "name": "Acme Corp - Enterprise License",
    "notes": "Contract under legal review",
    "owner_id": "f4a5b6c7-d8e9-0123-f012-456789012345",
    "probability": 75,
    "stage_id": "d2e3f4a5-b6c7-8901-def0-234567890123",
    "value": 75000
  }),
});

const data = await response.json();
```

**Python**

```python
import os

import requests

response = requests.patch(
    "https://api.versionseven.ai/v1/crm/deals/a47d043f-fc68-49de-bf05-8861f91f61e8",
    headers={
        "Authorization": f"Bearer {os.environ['VICTORIA_API_KEY']}",
    },
    json={
        "actual_close_date": "2024-03-15T00:00:00+00:00",
        "custom_fields": {
            "priority": "high",
        },
        "expected_close_date": "2024-03-31T00:00:00+00:00",
        "name": "Acme Corp - Enterprise License",
        "notes": "Contract under legal review",
        "owner_id": "f4a5b6c7-d8e9-0123-f012-456789012345",
        "probability": 75,
        "stage_id": "d2e3f4a5-b6c7-8901-def0-234567890123",
        "value": 75000,
    },
)
data = response.json()
```

## Headers

- `Authorization` (string, required): `Bearer` followed by a space and your API key, for example `Bearer vk_…`.

## Path parameters

- `deal_id` (string · uuid, required): ID of the deal.

## Request body

- `actual_close_date` (string · date-time or null, optional, at most 2,000 characters, example `"2024-03-15T00:00:00+00:00"`): Actual close date (set when deal is won/lost)
- `custom_fields` (object or null, optional): Custom fields as key-value pairs
- `expected_close_date` (string · date-time or null, optional, at most 2,000 characters, example `"2024-03-31T00:00:00+00:00"`): Expected close date
- `name` (string or null, optional, at most 2,000 characters, example `"Acme Corp - Enterprise License"`): Deal name/title
- `notes` (string or null, optional, at most 2,000 characters, example `"Contract under legal review"`): Deal notes
- `owner_id` (string · uuid or null, optional, at most 2,000 characters, example `"f4a5b6c7-d8e9-0123-f012-456789012345"`): ID of the deal owner (user)
- `probability` (integer or null, optional, ≥ 0, ≤ 100, example `75`): Win probability percentage (0-100)
- `stage_id` (string · uuid or null, optional, at most 2,000 characters, example `"d2e3f4a5-b6c7-8901-def0-234567890123"`): Move deal to a different stage
- `value` (number or null, optional, ≥ 0, example `75000`): Deal value in dollars

## Response

### `200`

```json
{
  "message": "string",
  "deal": {
    "name": "Acme Corp - Enterprise License",
    "actual_close_date": "2026-01-14T19:30:00+00:00",
    "created_at": "2024-01-15T10:30:00+00:00",
    "custom_fields": {},
    "expected_close_date": "2024-03-31T00:00:00+00:00",
    "id": "e3f4a5b6-c7d8-9012-ef01-345678901234",
    "lead_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "metadata": {},
    "notes": "Initial meeting scheduled for next week",
    "owner_id": "f4a5b6c7-d8e9-0123-f012-456789012345",
    "probability": 75,
    "stage_id": "d2e3f4a5-b6c7-8901-def0-234567890123",
    "updated_at": "2024-01-20T14:45:00+00:00",
    "value": 50000
  },
  "success": true
}
```

- `message` (string, required)
- `deal` (object, required): The updated deal
  - `name` (string, required, example `"Acme Corp - Enterprise License"`): Deal name/title
  - `actual_close_date` (string · date-time or null, optional): Actual close date (set when deal is won/lost)
  - `created_at` (string · date-time or null, optional, example `"2024-01-15T10:30:00+00:00"`): When the deal was created
  - `custom_fields` (object or null, optional): Custom fields as key-value pairs
  - `expected_close_date` (string · date-time or null, optional, example `"2024-03-31T00:00:00+00:00"`): Expected close date
  - `id` (string or null, optional, example `"e3f4a5b6-c7d8-9012-ef01-345678901234"`): Deal ID
  - `lead_id` (string or null, optional, example `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`): Associated lead ID
  - `metadata` (object or null, optional): Additional metadata
  - `notes` (string or null, optional, example `"Initial meeting scheduled for next week"`): Deal notes
  - `owner_id` (string or null, optional, example `"f4a5b6c7-d8e9-0123-f012-456789012345"`): ID of the deal owner (user)
  - `probability` (integer or null, optional, example `75`): Win probability percentage (0-100)
  - `stage_id` (string or null, optional, example `"d2e3f4a5-b6c7-8901-def0-234567890123"`): Current stage ID
  - `updated_at` (string · date-time or null, optional, example `"2024-01-20T14:45:00+00:00"`): When the deal was last updated
  - `value` (number or null, optional, example `50000`): Deal value in dollars
- `success` (boolean, optional, default `true`)

## Errors

Errors share one JSON body: `success`, `error`, `message`, optional `details`, and `request_id`. For example:

```json
{
  "success": false,
  "error": "UNAUTHORIZED",
  "message": "Invalid or inactive API key",
  "request_id": "734d11a1-54d4-414c-9e8d-4e1ada977db4"
}
```

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | The request didn't match the endpoint's schema: a missing or malformed field, a bad query parameter, or a value out of range. `details.errors` lists each failing field with its `field`, `message` and `type`. |
| 400 | `NO_UPDATES` | The update request contained no fields to change. |
| 400 | `INVALID_STAGE` | The `stage_id` in the request body isn't a stage in your organization. This is a `400` rather than a `404` for the same reason as `INVALID_LEAD`. |
| 400 | `INVALID_OWNER` | The `owner_id` in the request body isn't a member of your organization. This is a `400` rather than a `404` for the same reason as `INVALID_LEAD`. |
| 401 | `UNAUTHORIZED` | The `Authorization` header is missing or malformed, or the API key is unknown or has been deactivated. |
| 401 | `API_KEY_EXPIRED` | The API key is past its expiry date. Create a new key in the Victoria AI app. |
| 403 | `INSUFFICIENT_SCOPE` | The API key doesn't have the scope this endpoint requires, such as `leads:write`. |
| 403 | `ORGANIZATION_DEACTIVATED` | The organization that owns this API key has been deactivated. |
| 404 | `DEAL_NOT_FOUND` | No deal with this ID exists in your organization. |
| 404 | `NOT_FOUND` | No endpoint matches the path. A resource ID in the path that isn't a valid UUID also answers `NOT_FOUND`. |
| 413 | `PAYLOAD_TOO_LARGE` | The request body is larger than 1 MB. |
| 429 | `RATE_LIMITED` | Too many requests for this API key: more than 100 a minute to one endpoint, or 600 a minute in total. Retry after the number of seconds in the `Retry-After` header. See [Rate limits](https://docs.versionseven.ai/guides/rate-limits). |
| 500 | `INTERNAL_ERROR` | Something failed on our side. The response never includes internal details; quote its `request_id` when you contact support. |
| 503 | `UPSTREAM_TIMEOUT` | A service the API depends on timed out. The request is safe to retry. |
| 503 | `AUTH_UNAVAILABLE` | The API key couldn't be checked because the authentication service was unavailable. The request is safe to retry. |

## Response headers

| Header | Description |
| --- | --- |
| `X-Request-ID` | Correlation ID for the request, also returned as `request_id` in error bodies. Send your own `X-Request-ID`, up to 128 letters, digits, `.`, `_`, `:` or `-`, and it's used instead. |
| `RateLimit-Limit` | Requests allowed to this endpoint per minute. |
| `RateLimit-Remaining` | Requests you can still send to this endpoint right now. |
| `RateLimit-Reset` | Seconds until the endpoint's full limit is available again. |
| `Retry-After` | On a `429`: seconds to wait before retrying. |
