# Update a LinkedIn campaign

Steers a LinkedIn campaign of the user behind this key: pause it, resume it, archive it, set its daily limit, rename it, or send its invites without a note. Send only what changes. mySDR does the LinkedIn part of your outreach: you pick the people and write every text, mySDR sends it from the user's own LinkedIn account within their working hours and the SafeOutreach limits, notices accepted invites and replies, and stops a person's sequence when they reply. These routes are the tools `start_linkedin_sequence`, `get_outreach_status`, `get_outreach_events`, `get_replies`, `send_reply` and `stop_linkedin_sequence` of the assistant server, with the same bodies; your own emails you log with POST /outreach/activity. Free: no credits, except a month of unlimited LinkedIn outreach per account (750 credits, within the SafeOutreach limits; POST /outreach/linkedin/sequences).

**Pause** (`status: paused`): nothing of the campaign goes out until you resume it. Accepts and replies that come in meanwhile are still handled; the next step waits. **Resume** (`status: active`): steps that came due during the pause go out first, within working hours and the limits. When no month of unlimited LinkedIn outreach runs for the account, a resume turns one on (within the SafeOutreach limits): it is refused until you send `confirm_outreach_month: true` after the user said yes to unlocking that month. **Archive** (`status: archived`): only when nothing runs in it any more; stop it first with POST /outreach/linkedin/stop. An archived campaign stays archived and no longer shows in GET /outreach/linkedin.

A finished campaign (`completed`: every sequence in it stopped or ended) cannot be resumed: add people with POST /outreach/linkedin/sequences and its `campaign_id`, and it opens again.

**Notes on a free LinkedIn account.** A free account sends about 5 invitations with a note a month, each at most 200 characters. Past that (or when LinkedIn refuses a note sooner), invites with a note wait until the next month, while invites without a note and every other step keep going. A running sequence whose note is longer than that does not stop: its invite waits until the note is shortened (in the lead's window in mySDR) or goes without a note. `drop_invite_notes: true` sends them without their note instead.

## Authentication

Send `Authorization: Bearer gtk_…`. Create the key under **API keys in the menu**. 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 `campaign_id` from POST /outreach/linkedin/sequences or GET /outreach/linkedin.

### Body parameters

- **`status`** `string` — `paused`, `active` (resume) or `archived`. One of: `active`, `paused`, `archived`.
- **`daily_pace_limit`** `integer | null` — At most this many people of this campaign start per day, from 1 to 200; `null` removes it.
- **`name`** `string` — A new name, up to 80 characters.
- **`confirm_outreach_month`** `boolean` — `true` only after the user said yes to unlocking a month of unlimited LinkedIn outreach for this account (750 credits, within the SafeOutreach limits) when resuming.
- **`drop_invite_notes`** `boolean` — `true`: every invite of this campaign that has not gone out goes without its note, and invites that waited for the note limit of a free LinkedIn account (about 5 a month) go out now. Only after the user chose it; it cannot be undone.

## Response

- **`object`** `string` · **required** — Always `linkedin_campaign`. One of: `linkedin_campaign`.
- **`id / name / status`** `string` · **required** — The campaign after the change.
- **`daily_pace_limit`** `integer | null` · **required** — Its daily limit; null = only the limits of the account.
- **`running`** `integer` · **required** — Sequences in it that still have a step to go.
- **`changed`** `string[]` · **required** — What changed: `status`, `name`, `daily_pace_limit`, `invite_notes`. Empty when it already was like that.
- **`credits_charged`** `integer` · **required** — 750 when this resume turned on a month of unlimited LinkedIn outreach for the account, otherwise 0.
- **`notes`** `string[]` · **required** — What the change means, in sentences to tell the user.
- **`next`** `string | null` · **required** — What to do now.
- **`dashboard_url`** `string` · **required** — The Leads table in mySDR on this campaign.

## Credits

Free, apart from a resume that turns on a month of unlimited LinkedIn outreach for the account (750 credits, within the SafeOutreach limits, only after `confirm_outreach_month: true`).

## Errors

- **400** `invalid_request` — An unknown field, nothing to change, a `status` other than `active`, `paused` or `archived`, a `daily_pace_limit` outside its range, an empty or too long `name`, or an id that is not a campaign id. Also a resume that would turn on a month of unlimited LinkedIn outreach (750 credits per account, within the SafeOutreach limits) without `confirm_outreach_month: true` (`param` is `confirm_outreach_month`; the campaign stays paused).
- **404** `not_found` — No LinkedIn campaign of this user has this id.
- **409** `invalid_state` — Archiving a campaign in which sequences still run (stop it first), resuming or pausing a finished or archived campaign, or the campaign changed at the same moment.
- **402** `insufficient_credits` — Resuming when no month of unlimited LinkedIn outreach runs and the balance is under 750 credits per account. The campaign stays paused.
- **409** `invalid_state` — The key has no user behind it, so there is no LinkedIn account to send from.
- **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/outreach/linkedin/campaigns/5e0c1a2b-3d4e-4f50-8a61-7b8c9d0e1f23" \
  -H "Authorization: Bearer $MYSDR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paused"
  }'
```

### JavaScript

```javascript
const response = await fetch('https://mysdr.app/api/v1/outreach/linkedin/campaigns/5e0c1a2b-3d4e-4f50-8a61-7b8c9d0e1f23', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "status": "paused"
  })
});
const body = await response.json();
```

### Python

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

payload = {
  "status": "paused"
}

request = urllib.request.Request(
    "https://mysdr.app/api/v1/outreach/linkedin/campaigns/5e0c1a2b-3d4e-4f50-8a61-7b8c9d0e1f23",
    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
{
  "object": "linkedin_campaign",
  "id": "5e0c1a2b-3d4e-4f50-8a61-7b8c9d0e1f23",
  "name": "CFOs who just raised",
  "status": "paused",
  "daily_pace_limit": 20,
  "running": 34,
  "changed": [
    "status"
  ],
  "credits_charged": 0,
  "notes": [
    "Paused: nothing of this campaign goes out until you resume it (status active). Accepts and replies that come in meanwhile are still handled; the next step waits."
  ],
  "next": "Resume it with PATCH /outreach/linkedin/campaigns/{id} and status active when the user says so.",
  "dashboard_url": "https://mysdr.app/en/gtm/leads?campaign=5e0c1a2b-3d4e-4f50-8a61-7b8c9d0e1f23"
}
```
