# Add a partner's posts to a campaign

> Make a partner from two social handles, capture their posts and file them in a campaign, from Claude over MCP, the CLI or the SDK, with the price shown first.

One job, three ways to do it: make a [partner](https://docs.missin.co.uk/help/partners/partners-and-posts.md) for `@test11` on Instagram and TikTok, pull their posts, and add them to your spring [campaign](https://docs.missin.co.uk/help/campaigns/campaigns.md). All three do the same job. Each needs a secret key at Write, because it creates a partner and starts a capture.

Create the key in Settings > Developers > Create key (https://app.missin.co.uk/settings/developers). Capturing spends credits, so each route shows you the price first and starts only at a price you approved.

## Do it

**Claude (MCP)**

[Connect Claude](https://developer.missin.co.uk/mcp/connect-claude.md) to your workspace, then ask for the outcome:

```text
Make a partner for @test11 on Instagram and TikTok, pull their posts and add them to my spring campaign.
```

Claude works through it with the task tools and stops when it needs you:

1. `save_partner` makes one partner with both handles, or finds the partner that already has them.
2. `quote_capture` prices a capture of both platforms. Claude tells you the credits and the price. Nothing is spent.
3. After your yes, `start_capture` starts it with the price you approved and files the captured posts under your spring campaign.
4. `get_capture_status` reports progress. Claude tells you when the posts arrive.

If two campaigns match "spring", Claude asks which one you meant instead of guessing.

**CLI**

Install and log in as in [the CLI page](https://developer.missin.co.uk/tools/cli.md), then run these in order. Names work where ids do: `--partner @test11` and `--campaign spring` are looked up for you.

```bash
missin partners save --name "Test 11" --handle instagram:test11 --handle tiktok:test11
missin capture quote --partner @test11 --platform instagram --platform tiktok
missin capture start --partner @test11 --platform instagram --platform tiktok --campaign spring --quoted-credits 120
missin capture get-status --run-id <run-id>
```

`missin capture quote` prints the credits and the price. Pass its credits as `--quoted-credits`. In a terminal, `missin capture start` shows the price again and asks `y/N`; with `--yes` it skips the question and sends the quoted price with the call, and a price that moved is never accepted for you. Use the run ids that `start` prints for `get-status`.

Posts your workspace already held keep their campaign. File them with:

```bash
missin posts assign-to-campaign --campaign spring --partner @test11
```

If a name matches several records, the command prints the candidates and exits with code 3. Run it again with one id.

**SDK**

The SDK has one function per operation, so you make the same steps yourself. Look up the network ids, create the partner and its handles, find the campaign, quote, then start each platform at its quoted price.

```ts
import { createMissinClient } from "@missin/sdk";

const missin = createMissinClient({ apiKey: process.env.MISSIN_API_KEY! });

const { allSocialNetworks } = await missin.partners.socialNetworksLookup({});
const networkId = (slug: string) => allSocialNetworks!.nodes.find((n) => n?.slug === slug)!.rowId;

const { createPartner } = await missin.partners.create({ body: { name: "Test 11", username: "@test11" } });
const partnerId = createPartner!.partnerId!;
for (const slug of ["instagram", "tiktok"]) {
  const { createPartnerSocialNetwork } = await missin.partners.createSocialNetwork({
    partnerId,
    socialNetworkId: networkId(slug),
    body: { handle: "test11", watched: true },
  });
  if (createPartnerSocialNetwork!.userErrors.length > 0) throw new Error(JSON.stringify(createPartnerSocialNetwork!.userErrors));
}

const { allCampaigns } = await missin.campaigns.list({ first: 5, filter: { name: { includesInsensitive: "spring" } } });
const campaignId = allCampaigns!.nodes[0]!.rowId; // more than one match? choose, do not guess

const surfaces = ["instagram-post", "tiktok-video"];
const { captureQuotes } = await missin.capture.quotes({ input: surfaces.map((surface) => ({ surface, targets: 1, cap: 30 })) });

for (const [i, surface] of surfaces.entries()) {
  const { dispatchPartnerCapture } = await missin.capture.dispatchPartner({
    surface,
    partnerIds: [partnerId],
    campaignId,
    maxPerPartner: 30,
    quotedCredits: captureQuotes[i]!.credits,
  });
  if (dispatchPartnerCapture!.userErrors.length > 0) throw new Error(JSON.stringify(dispatchPartnerCapture!.userErrors));
}
```

A write that fails validation does not throw: check `userErrors` after every call, as above. Show the user `captureQuotes` and get their approval before the dispatch loop. The server refuses a `quotedCredits` that no longer matches and answers with the new price in `userErrors` (code `quote_changed`): show it and ask again, never retry on your own. If your workspace has capture add-ons switched on, pass them in `addons` when you quote; the CLI and the MCP tools read your saved settings for you.

File posts the workspace already held with `missin.posts.setPartnerCampaign({ postIds, campaignId })`.

## When it needs you

- **Two matches.** A name that matches several records is a question, not an error. MCP returns a `needs_choice` result, and the CLI exits with code 3 and prints the candidates. Answer with one id.
- **A price that moved.** Between the quote and the start, the price can change. You see the new one and decide again; nothing starts at a price you did not approve.
- **A key that is too weak.** A Read key cannot create a partner or start a capture. See [Errors](https://developer.missin.co.uk/get-started/errors.md) for `insufficient_access`, and [Authentication](https://developer.missin.co.uk/get-started/authentication.md) for access levels.
- **Capture is asynchronous.** Starting returns runs, not posts. Check the runs, then list the posts.

## Next

The [CLI page](https://developer.missin.co.uk/tools/cli.md) covers spending and exit codes, the [SDK page](https://developer.missin.co.uk/tools/sdk.md) covers errors and retries, and [Pagination and filtering](https://developer.missin.co.uk/guides/pagination-and-filtering.md) shows how to list the posts that arrive.

Source: https://developer.missin.co.uk/guides/partner-to-campaign
