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

# Rep intelligence

> Persona, methodology, and coaching synthesis — async, batched, and queryable.

Rep intelligence layers run **across multiple analyses** to surface patterns no single call can show. Three async jobs:

* **`persona_assign`** — which of 5 sales archetypes does this rep most resemble?
* **`methodology_assign`** — what primary + secondary methodology do they use?
* **`synthesis`** — coaching summary with strengths, gaps, action plan, score trends

Each job is async (returns 202 + job\_id), polls a single `/intel-jobs/:job_id` endpoint until complete, and writes a result that's queryable via dedicated GET endpoints (`/persona`, `/methodology`, `/synthesis/latest`).

## When to run each

| Job                  | Cadence                            | When in the rep's lifecycle         |
| -------------------- | ---------------------------------- | ----------------------------------- |
| `persona_assign`     | Once on onboarding, then quarterly | After 5+ analyses exist for the rep |
| `methodology_assign` | Once on onboarding, then quarterly | After 5+ analyses exist for the rep |
| `synthesis`          | Weekly or on-demand                | Anytime the rep has 3+ recent calls |

## The `analysis_ids` vs `recording_urls` decision

Both async jobs accept either an explicit list of analysis UUIDs or a list of recording URLs. Pick based on what you have:

* **`analysis_ids`** — much faster (\~15–30s). The analyses are already complete; the job only does the meta-step. Use this when the rep has historical analyses already.
* **`recording_urls`** — slower (potentially several minutes). Each URL is run through the analysis pipeline first (with 30-day URL caching), then the meta-step runs. Use this for fresh onboarding when no analyses exist yet.

You can pass at most one — they're mutually exclusive.

## Example: assign a persona from existing analyses

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST \
    https://api.goparlay.io/v1/orgs/demo-acme/reps/alex-smith/persona/assign \
    -H "Authorization: Bearer pk_sandbox_YOUR_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d '{
      "analysis_ids": [
        "f2782fc7-5355-48bf-a314-d6bf90bc4907",
        "e667ee24-ac9a-4d8a-aebc-640b609ad213"
      ]
    }'
  ```

  ```javascript Node theme={null}
  const queued = await fetch(`${BASE_URL}/v1/orgs/demo-acme/reps/alex-smith/persona/assign`, {
    method: "POST",
    headers: { Authorization: `Bearer ${KEY}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
    body: JSON.stringify({
      analysis_ids: [
        "f2782fc7-5355-48bf-a314-d6bf90bc4907",
        "e667ee24-ac9a-4d8a-aebc-640b609ad213",
      ],
    }),
  }).then((r) => r.json());

  console.log(queued.job_id); // poll this
  ```
</CodeGroup>

You get back a 202 with `{ job_id, status: "queued", created_at }`.

## Polling the job

```bash theme={null}
curl https://api.goparlay.io/v1/orgs/demo-acme/reps/alex-smith/intel-jobs/<job_id> \
  -H "Authorization: Bearer pk_sandbox_YOUR_KEY"
```

When `status === "completed"`, `result` contains the assignment:

```json theme={null}
{
  "id": "fa278916-52bb-40a1-8dee-01a927f3faf4",
  "status": "completed",
  "result": {
    "persona": "hard_worker",
    "confidence": 0.9,
    "justification": "Across both calls, the rep consistently demonstrates a methodical and process-driven approach...",
    "secondary_persona": null
  },
  "cost_usd_cents": 1,
  "completed_at": "2026-04-24T18:53:28.435+00:00"
}
```

## Reading the assignment later

`/persona/assign` writes to `persona_assignments`. To read the latest at any time:

```bash theme={null}
curl https://api.goparlay.io/v1/orgs/demo-acme/reps/alex-smith/persona \
  -H "Authorization: Bearer pk_sandbox_YOUR_KEY"
```

History (every prior assignment, AI or manual) is at `/persona/history`.

## Manual override

If a manager knows the rep better than the model:

```bash theme={null}
curl -X PUT \
  https://api.goparlay.io/v1/orgs/demo-acme/reps/alex-smith/persona \
  -H "Authorization: Bearer pk_sandbox_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "persona": "challenger",
    "justification": "Veteran seller — 8 years of enterprise experience. AI-assigned hard_worker doesn't reflect this."
  }'
```

This appends to history with `source: "manual"`. The previous AI assignment is preserved in history but no longer the "current" one.

## Methodology — same shape, different output

Replace `/persona/` with `/methodology/` and the response shape becomes `{ primary, secondary }`:

```json theme={null}
{
  "primary": {
    "methodologies": { "slug": "spin", "name": "SPIN Selling", "description": "..." },
    "justification": "...",
    "source": "ai"
  },
  "secondary": {
    "methodologies": { "slug": "sandler", "name": "Sandler Selling System", "description": "..." },
    "justification": "...",
    "source": "ai"
  }
}
```

`secondary` may be `null`.

## Synthesis — the coaching report

Synthesis takes either `lookback_count` (newest N analyses) or `analysis_ids`:

```bash theme={null}
curl -X POST \
  https://api.goparlay.io/v1/orgs/demo-acme/reps/alex-smith/synthesis \
  -H "Authorization: Bearer pk_sandbox_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "lookback_count": 10 }'
```

Result shape:

```json theme={null}
{
  "result": {
    "summary": "This rep is demonstrating strong foundational selling skills...",
    "trend": { "direction": "improving", "note": "Call X demonstrates a noticeable uplift..." },
    "top_gaps": [
      { "category": "clarity", "observation": "...", "supporting_evidence": "..." }
    ],
    "action_plan": {
      "this_week": "Review call X and practice pausing instead of filler words...",
      "stretch": "Proactively address objections earlier using Sandler's Up-Front Contract..."
    },
    "score_averages": { "clarity": 87, "close": 91 /* etc */ }
  }
}
```

Read the latest at `/synthesis/latest`. History at `/synthesis`.

## Webhooks for these jobs

Subscribe to:

* `persona.assigned` — when `persona_assign` completes
* `methodology.assigned` — when `methodology_assign` completes
* `profile.synthesized` — when `synthesis` completes

Each carries `{ org_id, rep_id, job_id, result }`. See the [webhooks guide](/guides/webhooks).

## Doing this from MCP

```
For org "demo-acme" rep "alex-smith", assign a persona using their last 5 completed analyses, then generate a coaching synthesis with the same set. Show me both results side-by-side.
```

The model calls `assign_rep_persona`, polls, then `generate_rep_synthesis`, polls, and renders both for you.

## Cost + latency reference

| Job                  | Path                            | Latency          | Cost                |
| -------------------- | ------------------------------- | ---------------- | ------------------- |
| `persona_assign`     | analysis\_ids                   | 15–30s           | \~\$0.01            |
| `persona_assign`     | recording\_urls                 | 30s × N + 15–30s | \~$0.02 × N + $0.01 |
| `methodology_assign` | analysis\_ids                   | 15–30s           | \~\$0.01            |
| `methodology_assign` | recording\_urls                 | 30s × N + 15–30s | \~$0.02 × N + $0.01 |
| `synthesis`          | analysis\_ids / lookback\_count | 20–40s           | \~\$0.02            |
