# Update a company

Changes where a company stands in your work: its status with a reason, a snooze until the rescan, what it said, your next action, its general addresses and contact form, your own fields. Send only what changes. `{id}` is its `id`, one of its `saved_ids`, or its domain or LinkedIn page; a company that is not in the table yet is added by its domain or page (pass `name`). A status change is logged. mySDR keeps your whole process, so the user never needs a spreadsheet next to it: the state of each company and person (status with a reason, next action, email and contact points, your own fields), every email, reply and bounce you log, the exclusions, and a check before every send. The user sees all of it in the Leads and Companies tabs.

## Authentication

Send `Authorization: Bearer gtk_…`. Create the key under **Connect assistant → API keys**. Every `gtk_` key can call these routes, also while the Signals API is closed. A missing, invalid or revoked key is **401**.

### Path parameters

- **`id`** `string` · **required** — The row, a domain or a LinkedIn page (URL-encoded).

### Body parameters

- **`status`** `string` — `new` (in the work), `needs_decision` (waits for the user; say why in `status_reason`), `snoozed` (until `snooze_until`, then `new` again) or `archived` (out; say why). One of: `new`, `needs_decision`, `snoozed`, `archived`.
- **`status_reason`** `string | null` — Why, in a few words: "Below 50 FTE", "Rescan 23/11". Up to 500 characters.
- **`snooze_until`** `string | null` — The day the row comes back as `new`: a date (`2026-11-23`, 09:00 Brussels time) or an ISO time. Alone it snoozes the row.
- **`lead_status`** `string | null` — What they said. `not_interested` also stops LinkedIn for them and blocks a new sequence. One of: `interested`, `meeting`, `later`, `not_interested`.
- **`next_action`** `object | null` — Your next step and when: `at` (a date or ISO time), `kind` (`follow_up`, `recontact`, `rescan`, `approval`, `other`), `note`, and `email` when that step is an email you will send yourself: `{ "text", "subject", "step", "template", "to" }` (`text` required, up to 20,000 characters; `subject` up to 200 and `template` up to 80, as in POST /outreach/activity; `step` 1 to 20; `to` only if it is not the row’s address; `kind` defaults to `follow_up`). The user sees the planned email on Templates, with the emails you already logged above it, and GET /agenda gives it back on its day, so you keep no copy. A list (GET /tables/leads, /tables/companies) gives it without `text`; one row (GET /tables/leads/{id}, /tables/companies/{id}), the response of a change and GET /agenda give the text. Logging `email_sent` with the same `step` clears it (logged without a step, it clears one planned without a step), and so do a reply, a meeting, a bounce, an unsubscribe, a referral and `not_interested`; plan the next one. A new `next_action` replaces the current one and the email planned for it (`replaced` in the response gives them back); `null` clears both. GET /agenda lists the due ones.
- **`out_of_office_until`** `string | null` — Away until this day (from an out-of-office reply).
- **`contact_points`** `object[]` — Replaces the list of general addresses and contact forms: `{ "email": "jobs@acme.com", "label": "jobs", "source_url": "…", "email_status": "verified" }` or `{ "form": "https://acme.com/contact" }`. Up to 20.
- **`add_contact_points`** `object[]` — Adds or updates these (the same address or form is updated), keeping the others.
- **`fields`** `object` — Your own columns, merged with what is there: a name in lowercase letters, digits and `_` (`fte`, `ats`, `open_roles`) with a value (text, number, true/false) or `{ "value", "label", "source_url", "observed_at" }`; `null` removes one. Up to 40 per row. The user sees them as columns.
- **`campaign_id`** `string` — Put the row in this campaign (POST /outreach/campaigns, or one from a LinkedIn sequence).
- **`campaign_ids`** `string[]` — Replaces the campaigns of the row.
- **`stage`** `string | null` — One of the organization's own stages (GET /stages), by its key (`mql`) or its name ("MQL"); `null` clears it. A stage sits next to `status`: it stops nothing and changes no status. A change is logged.
- **`owner`** `string | null` — Who in the team follows the row up: `me` (the user behind the key), or the email address or user id of a colleague (GET /team); `null` clears it. A change is logged.
- **`note`** `string | null` — Your note on the row, up to 500 characters.
- **`name`** `string` — The name, when the company is added by its domain or page.

## Response

- **`id`** `string` · **required** — The row: what list, PATCH and DELETE take.
- **`object`** `string` · **required** — `person` or `company`.
- **`name`** `string` · **required** — Its name.
- **`domain`** `string | null` — Its domain.
- **`linkedin_url`** `string | null` — Its LinkedIn page.
- **`status`** `string` · **required** — Its status now.
- **`status_reason`** `string | null` — Why.
- **`snooze_until`** `string | null` — While snoozed: until when.
- **`lead_status`** `string | null` — What they said.
- **`next_action`** `object | null` — `at`, `kind`, `note`.
- **`out_of_office_until`** `string | null` — While out of office: until when.
- **`contact_points`** `object[]` — Its general addresses and forms.
- **`fields`** `object` — Your own fields.
- **`campaign_ids`** `string[]` — Its campaigns.
- **`stage`** `string | null` — Its stage.
- **`owner_id`** `string | null` — The user id of its owner.
- **`owner`** `object | null` — With `owner` or `stage` in the body: the owner (`id`, `name`, `email`).
- **`note`** `string | null` — Your note on the row.
- **`changed`** `boolean` · **required** — Something changed.
- **`replaced`** `object` — When this call set another next action (or `null`): the one it replaced, `{ next_action: { at, kind, note, email } }`, with the full text of its planned email, so you can put it back.
- **`added_to_table`** `boolean` · **required** — The row was not in the table before this call (a company by its domain or page).
- **`stopped_linkedin_sequences`** `integer` — With `lead_status` `not_interested`: the LinkedIn sequences that stopped.
- **`dashboard_url`** `string` · **required** — The table in mySDR.

## Credits

Free. This call never uses credits.

## Errors

- **400** `invalid_request` — An unknown field (`email` belongs to a person; a company has `contact_points`), nothing to change, or a value that is not valid.
- **404** `not_found` — No company matches, and the id is not a domain or page to add it by.
- **409** `invalid_state` — The key has no user behind it, so mySDR cannot record who did it.
- **401** `authentication_error` — The Authorization header is missing, or the key is unknown or revoked.
- **403** `permission_error` — API access is not part of your plan, or your account is suspended.
- **429** `rate_limit_error` — More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header.
- **503** `service_unavailable` — The API is temporarily unavailable. Retry later.
- **500** `internal_error` — Something went wrong on our side.

## Example

### cURL

```bash
curl -X PATCH "https://mysdr.app/api/v1/tables/companies/acme-logistics.example" \
  -H "Authorization: Bearer $MYSDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "snoozed",
    "snooze_until": "2026-11-23",
    "status_reason": "Rescan: only 2 open roles",
    "add_contact_points": [
      {
        "email": "jobs@acme-logistics.example",
        "label": "jobs",
        "source_url": "https://acme-logistics.example/contact",
        "email_status": "catch_all"
      }
    ],
    "fields": {
      "fte": {
        "value": 233,
        "label": "FTE",
        "source_url": "https://example.org/annual-accounts"
      },
      "ats": "Recruitee"
    }
  }'
```

### JavaScript

```javascript
const response = await fetch('https://mysdr.app/api/v1/tables/companies/acme-logistics.example', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "status": "snoozed",
    "snooze_until": "2026-11-23",
    "status_reason": "Rescan: only 2 open roles",
    "add_contact_points": [
      {
        "email": "jobs@acme-logistics.example",
        "label": "jobs",
        "source_url": "https://acme-logistics.example/contact",
        "email_status": "catch_all"
      }
    ],
    "fields": {
      "fte": {
        "value": 233,
        "label": "FTE",
        "source_url": "https://example.org/annual-accounts"
      },
      "ats": "Recruitee"
    }
  })
});
const body = await response.json();
```

### Python

```python
import json
import os
import urllib.request

payload = {
  "status": "snoozed",
  "snooze_until": "2026-11-23",
  "status_reason": "Rescan: only 2 open roles",
  "add_contact_points": [
    {
      "email": "jobs@acme-logistics.example",
      "label": "jobs",
      "source_url": "https://acme-logistics.example/contact",
      "email_status": "catch_all"
    }
  ],
  "fields": {
    "fte": {
      "value": 233,
      "label": "FTE",
      "source_url": "https://example.org/annual-accounts"
    },
    "ats": "Recruitee"
  }
}

request = urllib.request.Request(
    "https://mysdr.app/api/v1/tables/companies/acme-logistics.example",
    headers={
    "Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}",
    "Content-Type": "application/json"
    },
    data=json.dumps(payload).encode(),
    method="PATCH",
)
with urllib.request.urlopen(request) as response:
    body = json.load(response)
```

### Example response

```json
{
  "id": "sav_2b9e8d10-7f4a-4a51-8c2e-5d1f0a3b6c77",
  "object": "company",
  "name": "Acme Logistics",
  "domain": "acme-logistics.example",
  "linkedin_url": null,
  "status": "snoozed",
  "status_reason": "Rescan: only 2 open roles",
  "snooze_until": "2026-11-23T08:00:00.000Z",
  "lead_status": null,
  "next_action": null,
  "out_of_office_until": null,
  "contact_points": [
    {
      "kind": "email",
      "value": "jobs@acme-logistics.example",
      "label": "jobs",
      "source_url": "https://acme-logistics.example/contact",
      "email_status": "catch_all"
    }
  ],
  "fields": {
    "fte": {
      "value": 233,
      "label": "FTE",
      "source_url": "https://example.org/annual-accounts",
      "observed_at": "2026-10-23T09:00:00.000Z"
    },
    "ats": {
      "value": "Recruitee",
      "label": null,
      "source_url": null,
      "observed_at": "2026-10-23T09:00:00.000Z"
    }
  },
  "campaign_ids": [],
  "note": null,
  "changed": true,
  "added_to_table": true,
  "dashboard_url": "https://mysdr.app/en/gtm/companies"
}
```
