# Get results

> The growth scoreboard for a window ending now: per-channel sections for email, outbound, LinkedIn, SEO, AI answers and ads, each available with data or unavailable with a reason.

Canonical: https://revnu.com/docs/results
Last updated: 2026-10-21

The same scoreboard Revnu reads every time it wakes. Read-only: nothing this route returns can be changed through it.

```bash
curl -H "Authorization: Bearer $REVNU_API_TOKEN" "https://revnu.com/api/v1/results?since=1789000000000"
```

## Query

| Param | Meaning |
|---|---|
| `since` | Start of the window, epoch milliseconds, clamped to between 31 days and one hour ago. Default 24 hours ago. |

## Response

```json
{
  "results": {
    "window": { "from": 1789000000000, "to": 1789604800000 },
    "baseline": { "from": 1788395200000, "to": 1789000000000 },
    "harness": { "available": true, "data": { } },
    "email": {
      "available": true,
      "data": {
        "sent": 120,
        "sentBaseline": 96,
        "draftsAwaiting": 4,
        "tracking": { "available": false, "reason": "tracking_off" },
        "replies": {
          "available": true,
          "data": {
            "replies": 7,
            "bounces": 2,
            "repliedContacts": [{ "who": "Jo Park", "company": "Northwind", "agoDays": 1, "intent": "interested" }]
          }
        }
      }
    },
    "outbound": { "available": true, "data": { "routes": [ ] } },
    "linkedin": {
      "available": true,
      "data": {
        "invites": 14,
        "health": { "needsReauth": false, "pausedUntil": null, "pauseReason": null, "inviteHeadroom": 6 },
        "replies": { "available": true, "data": { "count": 3 } }
      }
    },
    "seo": {
      "available": true,
      "data": { "postsPublished": 2, "postsHeld": 1, "postsFailed": 0, "views": 340 }
    },
    "aeo": { "available": true, "data": { } },
    "ads": { "available": false, "reason": "no_campaigns" }
  }
}
```

The numbers above are an example of the shape, not real figures, and some fields are left out to keep it short. The tables below list every field. `baseline` is the equal-length window just before `window`, for comparisons such as `sent` against `sentBaseline`.

Each channel section is `{ "available": true, "data": {…} }`, optionally with `caveats`, or `{ "available": false, "reason": "…" }`. Zero and unknown are different numbers.

### Email

| Field | Meaning |
|---|---|
| `sent` | Emails sent in the window |
| `sentBaseline` | Emails sent in the baseline window |
| `draftsAwaiting` | Email drafts waiting in the review queue |
| `tracking` | Opens and clicks, a section of its own: unavailable with `tracking_off` when no tracking domain is set up or tracking is turned off |
| `replies.data.replies` | People who replied in the window, counted by when the reply arrived. Automatic replies are left out. |
| `replies.data.bounces` | Emails that bounced in the window |
| `replies.data.repliedContacts` | The newest five replies: `who`, `company`, `agoDays`, and `intent` when Revnu has read the reply |
| `replies.data.byIntent` | Replies grouped by intent, when at least one has been classified |

Reply rate is not a field: divide `replies` by `sent`. For everyone who replied, list [`GET /leads?status=replied`](https://revnu.com/docs/leads.md).

### LinkedIn

The LinkedIn section reads the workspace owner's connected LinkedIn account. Counts are for the window unless the table says otherwise.

| Field | Meaning |
|---|---|
| `invites` | Connection requests sent in the window. Requests LinkedIn turned away because you were already connected or already invited are left out. |
| `alreadyConnectedHits` | Requests that hit that already-connected or already-invited wall |
| `newDMs` | Messages that started a new conversation |
| `chatReplies` | Messages sent into a conversation that already existed |
| `inmails` | InMails sent |
| `baseline` | `{ invites, dms, inmails }` for the baseline window, where `dms` is `newDMs` plus `chatReplies` |
| `health.needsReauth` | `true` when the LinkedIn connection has expired. Reconnect it in the dashboard. |
| `health.pausedUntil` | Epoch milliseconds when Revnu's LinkedIn pause ends, or `null` when it isn't paused. Live state, not windowed. |
| `health.pauseReason` | A short plain-text reason for the pause, such as a rate limit or several provider errors in a row, or `null` |
| `health.inviteHeadroom` | Connection requests Revnu can still send today: the smaller of what is left of today's limit and this week's |
| `replies.data.count` | Conversations that got a reply in the window, counted by when the reply arrived |
| `accepts.data.count` | Connection requests accepted in the window, counted by when Revnu saw the connection |
| `scoreboard` | All-time requests and acceptances by list, `{ label, invites, maturedInvites, accepts }` each. `maturedInvites` counts requests at least 7 days old plus accepted ones, a fair base for an acceptance rate. |

Why LinkedIn pauses and when it resumes is in [Why Did LinkedIn Sending Stop?](https://revnu.com/docs/linkedin-paused.md). For one person's connection and conversation, use [`GET /linkedin/person`](https://revnu.com/docs/linkedin-person.md).

### SEO

The SEO section is about the blog Revnu writes for. `postsPublished` and `postsHeld` count only posts Revnu wrote, not ones you added yourself.

| Field | Meaning |
|---|---|
| `postsPublished` | Posts Revnu wrote that were published or exported in the window |
| `postsHeld` | Posts waiting for your review right now. Live, not windowed. |
| `postsFailed` | Posts started in the window that failed. A count only: the cause isn't returned. |
| `refreshes` | `{ applied, skipped }`: updates to live posts Revnu applied or skipped in the window |
| `views` | Views of your blog posts in the window. `viewsPrev` is the baseline window. |
| `genCostCents` | Revnu's estimated cost of writing the posts it finished in the window, in cents |
| `gsc` | Search Console clicks and impressions, a section of its own: `{ clicks, impressions, prevClicks, from, through, ourPosts }`. Unavailable with `not_connected`, `needs_reauth` or `no_data_yet`. |
| `gsc.data.ourPosts` | The same numbers for your blog pages only, with the top five pages in `top`. `null` until Revnu has page-level data. |
| `scoreboard` | The last 14 days by content type, plus up to five pages with impressions and no clicks |

Search Console reports a day or two late, so `gsc` covers a window shifted back by two days. `from` and `through` give the exact dates. `prevClicks` is `null`, not 0, when the data doesn't reach back that far.

### Outbound

Outbound is all-time, not windowed: one row per campaign in `routes`, sorted by sends. Each row has `route`, `delivered`, `replied`, `bounced` and `pending` (leads found but not yet sent), plus `ready` and `drafted` when Revnu could count them, and `sequence` with the campaign's approval state.

### Why a section is unavailable

| Reason | Meaning |
|---|---|
| `not_connected` | The channel isn't connected |
| `needs_reauth` | It was connected, but the connection has expired; reconnect it in the dashboard |
| `tracking_off` | Open and click tracking isn't set up or is turned off |
| `no_blog` | Revnu hasn't written for your blog yet |
| `no_campaigns` | No ad campaigns exist |
| `not_tracked` | AI-answer visibility hasn't been measured yet |
| `measurement_stalled` | AI-answer measurements exist but none are recent enough to use |
| `no_data_yet` | Connected, but nothing has arrived for this window yet |
| `no_writer_yet` | Revnu doesn't measure this number yet |
| `read_failed` | This section couldn't be read this time; the others still rendered. Retry. |

## What a read-only token can't tell you

Some questions have no field. These come only from asking Revnu in a [message](https://revnu.com/docs/agent-messages.md), which needs `agent:message`:

- **How a sending inbox's warm-up is going**, and when it will start sending. No route returns warm-up progress.
- **Why a blog post failed.** `postsFailed` is a count. The cause stays with Revnu.
- **The detail behind a LinkedIn pause** beyond `pauseReason`, and what Revnu will do about it.

A message is a request for work, so a token that can ask can also start work. [Authentication](https://revnu.com/docs/authentication.md#a-status-bot-that-can-also-explain) has the safest way to set that up.

## Responses

| Code | Meaning |
|---|---|
| 200 | `{ results }` |
| 400 | `since` is not epoch milliseconds |
| 401 | Missing, revoked or unknown token |
| 402 | `setup_pending`: the account hasn't started its trial |
| 403 | The token lacks `results:read` |
| 429 | Over the read limit; wait `Retry-After` seconds |

## Frequently asked questions

### Which scope does this need?

`results:read`. A token without it gets `403` with `requiredScope` in the body. `GET /me` shows a token's scopes. `results:read` can't send, publish, run or spend.

### How do I get reply rate?

Divide `email.data.replies.data.replies` by `email.data.sent` for the same window, after checking both are available. [Pull Results Into Reporting](https://revnu.com/docs/pull-results-into-reporting.md) has a weekly Slack post that does it.

### Why is a channel unavailable instead of zero?

So a 0 always means a measured zero. Revnu marks a channel unavailable, with the reason in `reason`, when it has no measurement for it yet.

### Why is LinkedIn paused, and until when?

Read `linkedin.data.health.pausedUntil` (epoch milliseconds, or `null` when it isn't paused) and `pauseReason`. [Why Did LinkedIn Sending Stop?](https://revnu.com/docs/linkedin-paused.md) explains the pauses.

### Does the API show sending inbox warm-up progress?

Ask Revnu with a [message](https://revnu.com/docs/talk-to-your-agent.md), which needs `agent:message`. Warm-up progress comes from the agent rather than a results field.

### Can I read more than 31 days?

Each call covers up to 31 days. Pull daily and keep your own history for longer ranges.

### Are responses cached?

No. Every response is `Cache-Control: no-store`, so what you read is current.
