> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vegaminds.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Delete a contact



## OpenAPI

````yaml /openapi.yaml delete /contacts/{contact_id}
openapi: 3.1.0
info:
  title: Vega API
  version: '1'
  contact:
    name: Vega support
    email: support@vegaminds.com
  description: >
    The Vega API connects approved software to Vega, the workspace financial
    advisors use to manage their client

    relationships. Once a Vega user connects your application, your server reads
    and writes that user's contacts,

    households, notes, tasks, meetings, workflows and opportunities, acting as
    the user. Existing meeting

    preparations, notes, email drafts, transcripts and recordings are read-only.


    It is a JSON REST API at `https://api.vegaminds.com/v1`, authorized with
    OAuth 2.0.


    ## Getting access


    Vega approves each integration. To request access, write to
    support@vegaminds.com with the name of your product,

    what your integration does, the scopes it needs and its redirect URIs. Vega
    registers your application and sends

    you its `client_id` and `client_secret`.


    There is no separate sandbox. Vega sets up a firm of your own in Vega, with
    your developers as its users, to build

    and test your integration in.


    Partner integrations are off by default in every firm. A firm admin turns on
    **Partner integrations** in the

    firm's settings in Vega before the firm's users can connect your
    application.


    ## Authorization


    The API uses the OAuth 2.0 authorization code flow (RFC 6749) with PKCE (RFC
    7636, method `S256`), for

    confidential clients. A connection acts as the user who approved it: it sees
    and changes what that user can see

    and change in Vega, nothing more.


    **1. Send the user to Vega.** Create a random `code_verifier` (43 to 128
    characters from `A-Z`, `a-z`, `0-9` and

    `-._~`) and its `code_challenge`, the base64url encoded SHA-256 of the
    verifier, without padding. Then send the

    user's browser to:


    ```

    https://api.vegaminds.com/oauth/authorize
      ?response_type=code
      &client_id=YOUR_CLIENT_ID
      &redirect_uri=https%3A%2F%2Fapp.example.com%2Fvega%2Fcallback
      &scope=contacts%3Aread%20notes%3Awrite
      &state=RANDOM_STATE
      &code_challenge=CODE_CHALLENGE
      &code_challenge_method=S256
    ```


    `scope` lists exactly the scopes your integration needs, separated by
    spaces. `redirect_uri` must match one of

    your registered redirect URIs exactly.


    **2. The user approves.** The user logs in to Vega, reviews the permissions
    and allows the connection. Vega sends

    the browser back to your `redirect_uri` with `code`, `state` and `iss`
    (`https://api.vegaminds.com`). Check that

    `state` is the value you sent. If the user declines, or the request is
    invalid, the redirect carries `error` and

    `error_description` instead.


    **3. Exchange the code for tokens** from your server, within five minutes:


    ```

    curl https://api.vegaminds.com/oauth/token \
      -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
      -d grant_type=authorization_code \
      -d code=AUTHORIZATION_CODE \
      -d code_verifier=CODE_VERIFIER \
      --data-urlencode redirect_uri=https://app.example.com/vega/callback
    ```


    ```json

    {
      "access_token": "ACCESS_TOKEN",
      "token_type": "Bearer",
      "expires_in": 3600,
      "refresh_token": "REFRESH_TOKEN",
      "scope": "contacts:read notes:write"
    }

    ```


    **4. Call the API** with the access token:


    ```

    curl https://api.vegaminds.com/v1/me -H "Authorization: Bearer ACCESS_TOKEN"

    ```


    **5. Refresh** when the access token expires, after one hour:


    ```

    curl https://api.vegaminds.com/oauth/token \
      -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
      -d grant_type=refresh_token \
      -d refresh_token=REFRESH_TOKEN
    ```


    Each refresh returns a new refresh token and retires the one you sent: store
    the new one before you use it. A

    refresh repeated within 10 minutes, such as a retry after a timeout, is
    honored. A retired refresh token presented

    later ends the connection.


    A connection stops working when it is revoked, when the user leaves the
    firm, when the firm turns partner

    integrations off, or after a year without a refresh. The API then answers
    `401` and the token endpoint

    `invalid_grant`: the user connects again from your product.


    Offer a way to disconnect in your product. It calls `POST /oauth/revoke`
    with the refresh token, which ends the

    connection. Tokens and the client secret stay on your server: never send
    them to a browser.


    ## Scopes


    | Scope | Shown to the user | Covers |

    | --- | --- | --- |

    | `contacts:read` | Read your contacts and households | Reading contacts,
    households, contact types and household types |

    | `contacts:write` | Create, update and delete your contacts and households
    | Creating, updating and deleting contacts and households |

    | `notes:read` | Read your notes and the clients they are linked to |
    Reading notes |

    | `notes:write` | Create, update and delete your notes | Creating, updating
    and deleting notes |

    | `tasks:read` | Read your tasks, their assignees and the clients they are
    linked to | Reading tasks |

    | `tasks:write` | Create, update and delete your tasks | Creating, updating
    and deleting tasks |

    | `workflows:read` | Read your workflows and the templates you can use |
    Reading runs and usable templates |

    | `workflows:write` | Start workflows, update their names, tags and roles,
    and move them between stages | Starting, editing and moving runs |

    | `opportunities:read` | Read your opportunities and your firm's pipelines |
    Reading opportunities and pipelines |

    | `opportunities:write` | Create and update your opportunities, including
    their pipeline, stage and status | Creating, editing, moving, closing and
    reopening opportunities |

    | `meetings:write` | Create, update and delete your meetings | POST, PATCH
    and DELETE on meetings |

    | `meetings:read` | Read your meetings, preparations, notes, email drafts,
    transcripts and recordings | Reading meetings and their existing artifacts |

    | `tags:read` | Read your firm's tags | Listing and reading the tag catalog
    |

    | `tags:write` | Create, rename and delete your firm's tags (admins only) |
    Managing tag definitions, not record assignments |

    | `users:read` | See the names and email addresses of the people in your
    firm | Listing users |


    Each operation needs exactly one scope, and a write scope does not include
    the read scope. `GET /me` needs only a

    valid access token. A request without the scope it needs answers `403
    insufficient_scope`: the user connects

    again, and your authorization request asks for the scope.


    ## Conventions


    - **Requests and responses** are JSON in UTF-8. Send `Content-Type:
    application/json` with a request body.

    - **Ids** are opaque strings (UUIDs) that Vega assigns. A create never
    accepts an id.

    - **Dates** are `YYYY-MM-DD`. **Timestamps** are ISO 8601 with a time zone
    offset: Vega returns them in UTC
      (`2026-11-10T21:40:12Z`) and accepts any offset.
    - **Lists** take `page` (1 to 1,000) and `limit` (1 to 100 records per page,
    default 50), and answer
      `{"data": [...], "page": 1, "limit": 50, "has_more": true}`. There are no totals: read pages until `has_more`
      is `false`. List rows are summaries, and a record's own URL returns all of its fields.
    - **Changes.** The contact, household, note and task lists take
    `updated_after`, which keeps the records whose
      `updated_on` is at or after a timestamp, so a sync reads only what changed since the last one. `updated_on`
      moves when a record's own fields change, not when only its lists do: a contact's email addresses, phone numbers
      or mailing addresses, a household's members, the clients or tags linked to a note or a task. A deleted record leaves
      the lists, and its URL answers `404`.
    - **A single record** is returned as it is, without a wrapper.

    - **Create** answers `201` with the record (only `{id}` for meetings,
    workflows and opportunities), and its URL in the
      `Location` header. Repeating a create makes a
      second record: after a timeout, check whether the first one exists before trying again.
    - **Update** is `PATCH`. A field left out is unchanged, and `null` clears a
    field that allows it. A list sent
      replaces the whole list, and `[]` empties it.
    - **Delete** answers `204`. The record then answers `404`.

    - **Unknown fields and query parameters are rejected** with `400`, never
    ignored. So is text that contains the
      null character.
    - **Additions.** Responses can gain fields, and fields can gain values.
    Ignore what you do not recognize.

    - **Visibility.** A record the user cannot see, a deleted record and an id
    that never existed all answer `404`.


    ## Errors


    Errors share one format:


    ```json

    {
      "error": {
        "code": "invalid_request",
        "message": "The request body is invalid.",
        "fields": {
          "email_addresses[0].address": "Must be an email address."
        }
      },
      "request_id": "3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16"
    }

    ```


    `code` is stable and meant for your code. `message` is meant for people and
    can change. `fields`, on validation

    errors, names each invalid input. Every `/v1` response carries an
    `X-Request-Id` header with the same id as

    `request_id`: include it when you contact support.


    | Status | Code | Meaning |

    | --- | --- | --- |

    | 400 | `invalid_request` | The request is malformed, or a value is invalid.
    |

    | 401 | `invalid_token` | The access token is missing, invalid, expired or
    revoked, or the connection ended. |

    | 403 | `insufficient_scope` | The connection lacks the scope the operation
    needs. |

    | 403 | `plan_required` | The connected user has no Vega plan that includes
    API access. |

    | 403 | `admin_required` | Only a current firm admin may create, rename or
    delete tag definitions. |

    | 404 | `not_found` | No such record or URL, or the user cannot see the
    record. |

    | 405 | `method_not_allowed` | The URL exists, but not with this method. |

    | 409 | `external_record` | This record has an active integration link.
    Change it in the source application; meetings may patch reviewed alone. |

    | 409 | `conflict` | The workflow changed stage, or a tag name already
    exists. Read current state before retrying. |

    | 429 | `rate_limited` | Too many requests. See the rate limit below. |

    | 500 | `internal_error` | An error on Vega's side. Try again later. |


    The OAuth endpoints answer in the standard OAuth format instead:

    `{"error": "invalid_grant", "error_description": "..."}`.


    ## Behaviour to know


    - Records created through the API are owned by the connected user, and
    shared as that user's default sharing
      settings in Vega say.
    - Assigning a task to someone else notifies them in Vega and by email, and
    changing a task assigned to someone
      else notifies them in Vega, as in Vega. Changing the status of a task that belongs to a workflow, or deleting
      it, moves the workflow forward, as in Vega.
    - Contacts, households, notes, tasks and meetings return `is_external` on
    list and detail responses. True means
      an active integration association, including a record exported from Vega, not necessarily where it was created.
      Links to external contacts or households do not make the parent record external. A disconnected or deleted
      integration no longer counts. Workflows and opportunities are Vega-native and have no integration associations.
    - PATCH and DELETE of an external record return `409 external_record`;
    change it in the source application.
      Meetings may patch `reviewed` alone. A mixed patch is rejected in full. This API never writes through to a CRM
      or calendar. A local create does not create an association. The flag is read-only, and does not grant permission:
      scope and visibility still apply. The server rechecks association state before dispatching every mutation.
      This preflight is not a transaction lock against a simultaneous sync/export attaching the record.
      Synced values can fall outside documented input enums, such as a task status or contact type.
    - A firm can require fields beyond the ones documented here. A create that
    misses one answers `400`, with a
      message that names the field.
    - The API returns current state, with no change feed. Meetings, workflows
    and opportunities have no `updated_after`
      filter; an integration that mirrors them reads the lists again.

    ## Tags


    Read the firm catalog at `GET /tags` with `tags:read`. Notes, tasks,
    workflows and opportunities accept

    `tag_ids` on create and PATCH, using that resource's write scope. Each id
    must be an active tag from the same

    firm, appear once, and the list may contain at most 100 ids. Omit it to keep
    tags unchanged, or send `[]` to

    clear them; `null` is rejected. Detail reads return `tags: [{id, name}]`;
    resource lists stay compact.

    Tag-only edits of external notes or tasks still return `409
    external_record`. Contacts, households and meetings

    do not support tag assignments. There is no tag filter on resource lists.


    `tags:write` manages definitions and requires a current firm admin: create,
    rename and delete affect the whole

    firm. Deletion hides a tag from every record's tag list without deleting
    those records. Assigning an existing

    tag needs neither admin rights nor a tag scope. Existing connections need
    fresh consent to add catalog scopes.

    Workflow starts commit before their best-effort tag assignment: read the
    returned workflow and, if needed,

    PATCH its tags. Do not repeat POST to repair tags. Tag changes are not a
    reliable `updated_after` feed.


    ## Rate limit


    600 requests per source IP per rolling five minutes, two a second on
    average; short bursts are fine. Over the limit, the API

    answers `429` with `Retry-After: 60` and a body without `request_id`. Wait
    that many seconds, then continue.
servers:
  - url: https://api.vegaminds.com/v1
security:
  - oauth2: []
tags:
  - name: Authorization
    description: >-
      The OAuth 2.0 endpoints that connect a user to your application and issue
      tokens. They are served at `https://api.vegaminds.com/oauth`, outside
      `/v1`.
  - name: Me
    description: The connected user.
  - name: Users
    description: The people in the connected user's firm.
  - name: Contacts
    description: >-
      The people and companies the firm works with, and the firm's contact
      types.
  - name: Households
    description: Groups of contacts, such as a family, and the firm's household types.
  - name: Notes
    description: Notes, linked to the contacts and households they are about.
  - name: Meetings
    description: >-
      Read meetings and their latest preparation and note, email drafts,
      transcript and recordings.
  - name: Tasks
    description: Tasks with a due date and an assignee, linked to contacts and households.
  - name: Workflows
    description: >-
      Start and track runs of existing templates, update tags/roles and move
      between stages. Template authoring stays in Vega.
  - name: Opportunities
    description: >-
      Discover pipelines, create and update opportunities, move between stages,
      close and reopen. Pipeline authoring stays in Vega.
  - name: Tags
    description: Discover firm tags and, as an admin, manage the catalog.
paths:
  /contacts/{contact_id}:
    parameters:
      - $ref: '#/components/parameters/contact_id'
    delete:
      tags:
        - Contacts
      summary: Delete a contact
      operationId: delete_contact
      responses:
        '204':
          description: Deleted.
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/InvalidToken'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/ExternalRecord'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - oauth2:
            - contacts:write
components:
  parameters:
    contact_id:
      name: contact_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  responses:
    InvalidRequest:
      description: '`invalid_request`: the request is malformed, or a value is invalid.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: invalid_request
              message: The request body is invalid.
              fields:
                email_addresses[0].address: Must be an email address.
            request_id: 3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16
    InvalidToken:
      description: >-
        `invalid_token`: the access token is missing, invalid, expired or
        revoked, or the connection ended.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: invalid_token
              message: The access token is invalid, expired or revoked.
            request_id: 3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16
    Forbidden:
      description: >-
        `insufficient_scope`: the connection lacks the scope the operation
        needs. `plan_required`: the connected user has no Vega plan that
        includes API access.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: insufficient_scope
              message: >-
                This request needs the contacts:write scope, which the user did
                not grant. Connect the user again, asking for it.
            request_id: 3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16
    NotFound:
      description: '`not_found`: no such record, or the user cannot see it.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: not_found
              message: Contact not found.
            request_id: 3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16
    ExternalRecord:
      description: >-
        `external_record`: the visible record has an active integration
        association. Change it in the source application. Meetings may patch
        reviewed alone.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: >-
        `rate_limited`: too many requests. Wait the number of seconds in
        `Retry-After`.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: rate_limited
              message: >-
                Too many requests. Wait the number of seconds in the Retry-After
                header, then try again.
    InternalError:
      description: '`internal_error`: an error on Vega''s side. Try again later.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: internal_error
              message: >-
                Something went wrong on our side. Try again later, and contact
                Vega support with the request id if it keeps happening.
            request_id: 3f6c1e9a-2b7d-4c58-9e41-8a0d5b7f2c16
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable, for your code. One of the codes in the errors table.
            message:
              type: string
              description: For people. Can change.
            fields:
              type: object
              description: >-
                On validation errors, each invalid input and what is wrong with
                it. A key is the input's path, such as
                `email_addresses[0].address`.
              additionalProperties:
                type: string
        request_id:
          type: string
          description: >-
            Also in the `X-Request-Id` header. Absent on a `429` from the rate
            limit.
  headers:
    RetryAfter:
      description: Seconds to wait before the next request.
      schema:
        type: integer
  securitySchemes:
    oauth2:
      type: oauth2
      description: >-
        OAuth 2.0 authorization code flow with PKCE (S256). See the
        authorization guide.
      flows:
        authorizationCode:
          authorizationUrl: https://api.vegaminds.com/oauth/authorize
          tokenUrl: https://api.vegaminds.com/oauth/token
          refreshUrl: https://api.vegaminds.com/oauth/token
          scopes:
            contacts:read: Read your contacts and households
            contacts:write: Create, update and delete your contacts and households
            notes:read: Read your notes and the clients they are linked to
            notes:write: Create, update and delete your notes
            tasks:read: >-
              Read your tasks, their assignees and the clients they are linked
              to
            tasks:write: Create, update and delete your tasks
            workflows:read: Read your workflows and the templates you can use
            workflows:write: >-
              Start workflows, update their names, tags and roles, and move them
              between stages
            opportunities:read: Read your opportunities and your firm's pipelines
            opportunities:write: >-
              Create and update your opportunities, including their pipeline,
              stage and status
            meetings:write: Create, update and delete your meetings
            meetings:read: >-
              Read your meetings, preparations, notes, email drafts, transcripts
              and recordings
            tags:read: Read your firm's tags
            tags:write: Create, rename and delete your firm's tags (admins only)
            users:read: See the names and email addresses of the people in your firm

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.