# 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-11-07

The same scoreboard Revnu reads before it decides what to do next. 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 },
    "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 the fields you will use. `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 connection 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. |
| `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.
