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

# What stops a statement from posting to the ledger in full

> **GET /publisher/statements/{id}/setup-checklist**

> [!NOTE]
>
> This endpoint requires authentication. Include your Bearer token in the Authorization header.

## Description

**GET /publisher/statements/{id}/setup-checklist**

Runs the ledger post as a dry run and returns what it would refuse,
grouped by the bridge's own reasons, so the client can show what to fix
before posting. Works for any publisher statement (manual, Reconcile
wizard or built from files), in every payee mode (`publisher`,
`writer_collected`, `writer_at_source`), posted or not. **Read-only**: it
never writes a ledger transaction or entry and never opens a transaction.

`data.groups` always carries every key; an empty group has `count: 0` and
`items: []`. The keys are the writer reasons `no_tenant_user`,
`no_payee_writer`, `payee_writer_not_found`, `no_active_agreement`,
`no_agreement_in_period`, `no_agreement_territory`, `no_manuscript_share`
and `negative_net`, then `worksWithoutWriters`, `zeroShareWorkWriters` and
`missing_fx` (a non-USD statement with no exchange rate; the rest of the
list is still computed). Every item has `writerId` (null where there is no
writer record), `publisherId`, `gross` and `currency`. Unmatched
participants all have a null `writerId`; tell them apart by `participant`
(`name`, `ipi`) or by `key`.

`negative_net` items come from the dry run (`source: live`) and, for a
statement built from files, from the net the build recorded. A writer the
dry run listed under any reason is described once, there, and the recorded
entry is skipped. A recorded writer entry the dry run never placed belongs to
a writer with no matched lines left, so it is out of date: it is returned as a
warning (`source: build`, `liveConfirmed: false`, `warning: true`, `gross: 0`,
`storedNet`). A recorded work entry (publisher mode) is re-checked against the
lines now and dropped when it no longer nets negative.

`unmatched`, `disputed` and `held` are summed from the statement's lines
on every call, not read from the build summary, so a line held by a
rebuild is counted as held. `ready` is true when no blocking group has an
item; unmatched, disputed and held lines are reported apart.

**Do not add `gross` across groups.** Each group says so with `additive`.
`missing_fx` carries the whole matched gross (every other group is a slice
of it), `zeroShareWorkWriters` carries 0, and a `negative_net` is already
inside its writer's group or the postable gross (for example a work that nets
-5 in publisher mode is already part of the gross of a writer with no active
agreement), so adding it again would double count.

Some items are warnings (`warning: true`, and `warning: true` on the group
when all its items are): they do not block a post, so they are counted in
`summary.warnings`, not `summary.items`, and do not change `ready`. These are
every `zeroShareWorkWriters` item (a writer on a work with a 0% share is owed
nothing there, because the work's money goes to its other writers; the work's
total is context in `workGross`, and a writer already under
`no_manuscript_share` is not repeated) and a recorded `negative_net` for a
writer with no matched lines left (see below; `gross` is 0 and the recorded net
is in `storedNet`).
Amounts keep ledger precision (6 decimal places); round for display.

A statement the ledger refuses to post (a client statement under an
administration agreement, an unrecognised payee mode) answers 422 with the
original `code`.

**Authorization:** `admin` role + `publisher` capability enabled.

## Code Examples

```javascript Node.js theme={null}
const response = await fetch('https://api.royalti.io/publisher/statements/example-id/setup-checklist', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const data = await response.json();
console.log(data);
```

```python Python theme={null}
import requests

response = requests.get(
  'https://api.royalti.io/publisher/statements/example-id/setup-checklist',
  headers={
    'Authorization': f'Bearer {token}'
  }
)

data = response.json()
print(data)
```

```bash cURL theme={null}
curl -X GET https://api.royalti.io/publisher/statements/example-id/setup-checklist \
  -H "Authorization: Bearer YOUR_TOKEN"

```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.