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

# Partner analytics API: live order and evidence metrics

> Read a request-time analytics snapshot for your partner orders, including volume, lifecycle funnel, turnaround, service mix, evidence counts, and revenue.

`GET /api/partner/analytics`

Returns a request-time snapshot computed exclusively over orders created with your partner account. The endpoint reads the transactional order records directly; it does not return another partner's orders and does not use an eventually consistent analytics export.

The reporting window is a **creation cohort**. An order is included when its `createdAt` falls between the request time minus `windowDays` and the request time, inclusive. Funnel, completion, evidence, service, and revenue figures then use the current records for that cohort. They are not counts of events that occurred during the window.

<Check>
  **Tenancy guarantee:** every figure is computed exclusively over orders
  created with your partner account. Document, shipment, and workflow-event
  queries are constrained to order IDs from that partner-scoped cohort.
</Check>

## Authentication

This route accepts either credential:

* **Partner API key** — `Authorization: Bearer sss_pk_...` for server-to-server reads.
* **Linked dashboard session** — the SignSealShip session cookie for a signed-in user linked to a partner account.

Bearer-key authentication runs first. If the key resolves, its partner account selects the tenant even when a session cookie is also present. If the key is missing or does not resolve, the route falls back to the session.

That fallback determines the error semantics:

```json 401 Unauthorized theme={null}
{ "error": "Sign in to continue." }
```

`401` means that no bearer key resolved and there is no valid signed-in session. A bad bearer key can still succeed when the request also carries a valid linked session.

```json 403 Forbidden theme={null}
{ "error": "This session is not linked to a partner. Link with a partner API key first." }
```

`403` means the session is valid but is not linked to a partner account. See [authentication](/api-reference/authentication) for key-handling guidance.

## Query parameter

<ParamField query="days" type="integer" default="90">
  Requested creation-window length. The service clamps the value to `1..366`
  instead of rejecting an out-of-range integer: values below 1 become 1 and
  values above 366 become 366. The effective value is returned as
  `windowDays`.
</ParamField>

## Example

```bash curl theme={null}
curl "https://signsealship.com/api/partner/analytics?days=90" \
  -H "Authorization: Bearer sss_pk_your_key"
```

```json 200 OK theme={null}
{
  "windowDays": 90,
  "volumeByMonth": [
    { "month": "2026-05", "createdCount": 8, "completedCount": 4 },
    { "month": "2026-06", "createdCount": 10, "completedCount": 3 },
    { "month": "2026-07", "createdCount": 13, "completedCount": 5 },
    { "month": "2026-08", "createdCount": 4, "completedCount": 1 }
  ],
  "funnel": {
    "created": 6,
    "paid": 5,
    "inProgress": 7,
    "completed": 13,
    "problem": 4
  },
  "turnaroundHours": {
    "median": 19.75,
    "p90": 51.6
  },
  "serviceMix": {
    "sign": 25,
    "notarize": 17,
    "ship": 12,
    "fax": 3
  },
  "evidence": {
    "totalCompleted": 13,
    "sealedDocumentCount": 16,
    "deliveredWithProofCount": 9
  },
  "revenueCents": 1843250,
  "generatedAt": "2026-08-02T17:42:18.451237+00:00"
}
```

## Response fields

<ResponseField name="windowDays" type="integer">
  Effective creation-window length after the `days` value is defaulted and
  clamped. Always from 1 through 366.
</ResponseField>

<ResponseField name="volumeByMonth" type="array">
  Creation-cohort counts grouped by the order's UTC creation month, ordered
  oldest to newest. Months with no included orders are omitted.

  <Expandable title="month bucket">
    <ResponseField name="month" type="string">
      UTC calendar month in `YYYY-MM` format.
    </ResponseField>

    <ResponseField name="createdCount" type="integer">
      Number of cohort orders created in this month, regardless of their
      current status.
    </ResponseField>

    <ResponseField name="completedCount" type="integer">
      Number of those same orders whose current status is exactly `Completed`.
      This is not the number of completion events that occurred in the month.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="funnel" type="object">
  One mutually exclusive current-status bucket per order in the cohort. The
  five counts always sum to the cohort's total order count.

  <Expandable title="funnel fields">
    <ResponseField name="created" type="integer">
      Orders currently in the `Created` funnel bucket. This is not total order
      volume; use the sum of `volumeByMonth[].createdCount` for that.
    </ResponseField>

    <ResponseField name="paid" type="integer">
      Orders currently in the `Paid` funnel bucket.
    </ResponseField>

    <ResponseField name="inProgress" type="integer">
      Orders currently in the `InProgress` funnel bucket.
    </ResponseField>

    <ResponseField name="completed" type="integer">
      Orders whose current status is exactly `Completed`.
    </ResponseField>

    <ResponseField name="problem" type="integer">
      Orders currently in a failure, hold, refund, cancellation, or other
      problem state. A status not recognized by the running service also fails
      closed into this bucket.
    </ResponseField>
  </Expandable>
</ResponseField>

### Funnel status contract

The mapping is explicit in the service. Status names are case-sensitive PascalCase values from the Order API.

| Response bucket | Order statuses counted                                                                                                                                                                             |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `created`       | `Created`, `QuoteReady`, `AwaitingPayment`                                                                                                                                                         |
| `paid`          | `Paid`                                                                                                                                                                                             |
| `inProgress`    | `EsignPending`, `EsignComplete`, `NotarizationPending`, `NotarizationComplete`, `ShippingPending`, `Shipped`, `Delivered`, `FaxPending`, `FaxSent`, `FaxDelivered`                                 |
| `completed`     | `Completed`                                                                                                                                                                                        |
| `problem`       | `PaymentFailed`, `EsignDeclined`, `EsignExpired`, `NotarizationFailed`, `IdentityLocked`, `ManualQuoteRequired`, `OnHold`, `ShippingFailed`, `RefundPending`, `Refunded`, `Cancelled`, `FaxFailed` |

<ResponseField name="turnaroundHours" type="object">
  Distribution of paid-to-completed durations for qualifying completed orders
  in the cohort.

  <Expandable title="turnaround fields">
    <ResponseField name="median" type="number">
      Continuous 50th-percentile duration in hours, rounded to two decimal
      places.
    </ResponseField>

    <ResponseField name="p90" type="number">
      Continuous 90th-percentile duration in hours, rounded to two decimal
      places.
    </ResponseField>
  </Expandable>
</ResponseField>

Only a `Completed` order with a recorded `payment.cleared` workflow event contributes to turnaround. The start is its earliest such event. The end is the order's current `updatedAt`, used as the completion stamp because the implementation does not yet have a durable order-completion event. An order with `updatedAt` before the payment event is excluded. When there are no qualifying samples, both values are `0`; zero therefore means **no measurable sample**, not necessarily instant completion. The response does not include the sample size.

<ResponseField name="serviceMix" type="object">
  Counts of cohort orders carrying each service flag. A multi-service order is
  counted once in every applicable field, so these values are not mutually
  exclusive and need not sum to the order count.

  <Expandable title="service fields">
    <ResponseField name="sign" type="integer">
      Orders that include the `Sign` service flag.
    </ResponseField>

    <ResponseField name="notarize" type="integer">
      Orders that include the `Notarize` service flag.
    </ResponseField>

    <ResponseField name="ship" type="integer">
      Orders that include the `Ship` service flag.
    </ResponseField>

    <ResponseField name="fax" type="integer">
      Orders that include the `Fax` service flag.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="evidence" type="object">
  Count-based evidence inventory for the cohort.

  <Expandable title="evidence fields">
    <ResponseField name="totalCompleted" type="integer">
      Cohort orders whose current status is exactly `Completed`. This equals
      `funnel.completed`.
    </ResponseField>

    <ResponseField name="sealedDocumentCount" type="integer">
      Number of attached order-document rows whose kind is exactly `sealed` or
      `notarized` across all cohort orders.
    </ResponseField>

    <ResponseField name="deliveredWithProofCount" type="integer">
      Number of attached shipment rows whose current shipment status is exactly
      `Delivered` across all cohort orders.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  **Evidence-count semantics — August 2, 2026:** the two evidence counters are
  artifact and shipment row counts, not unique-order counts or percentages.
  They are scoped to all orders in the creation cohort, not only orders in
  `totalCompleted`. A single order can contribute more than one matching row,
  so do not divide either field by `totalCompleted` and call the result a
  coverage percentage.
</Note>

<ResponseField name="revenueCents" type="integer">
  Sum of `totalCents` for cohort orders currently in the `paid`, `inProgress`,
  or `completed` funnel buckets. USD cents. It excludes `created` and `problem`
  orders and is a current-order-total metric, not a payment-ledger balance.
</ResponseField>

<ResponseField name="generatedAt" type="string">
  ISO 8601 UTC timestamp generated by the API for this response. The response
  does not include separate window-start or window-end fields.
</ResponseField>

## Errors and rate limiting

| Status                  | Meaning                                                                                                     |
| ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`       | `days` could not be bound as an integer. Out-of-range integers do not produce this error; they are clamped. |
| `401 Unauthorized`      | No bearer key resolved and there is no valid session.                                                       |
| `403 Forbidden`         | The valid session is not linked to a partner account.                                                       |
| `429 Too Many Requests` | The fixed one-minute analytics limit has been exceeded.                                                     |

The route uses the `partner-portal` limit: **120 requests per minute**. A request carrying a dashboard session cookie is bucketed by that session; otherwise it is bucketed by client IP, including bearer-key-only requests. Back off until the fixed one-minute window resets after a `429`.
