---
title: "List interaction receipts"
method: GET
path: "/products/notify/receipts"
tags: ["notify"]
---

# List interaction receipts

`GET /products/notify/receipts`

Verified-interaction proofs across the account, newest first. `source` says which store answered: `receipt_index` is the normal path, with real pagination; `legacy_scan` serves an account whose receipts all predate that index by filtering the audit log, which can return EMPTY pages mid-walk. On either source, follow the cursor until it is null before concluding there are none. The two are never merged, and a cursor always resumes on the source that issued it.

## Query parameters

- `limit` integer
- `cursor` string
- `interaction` 'view' | 'acknowledge' | 'sign' | 'approve' | 'reply'

## Response `200`

A page of receipts.

- object
  - `data` object, required
    - `receipts` NotifyReceipt[], required
      - `event_type` 'sparklink_accessed' | 'sparklink_signed' | 'sparklink_approved' | 'sparklink_denied' | 'sparklink_replied', required
      - `occurred_at` integer, nullable, required — Unix seconds.
      - `interaction` 'view' | 'acknowledge' | 'sign' | 'approve' | 'reply' | 'null', nullable, required
      - `identity` string, nullable — The verified identity that performed the interaction.
      - `asset_id` string, nullable
      - `vault_id` string, nullable
      - `link_code` string, nullable — Masked pointer code (6-char display prefix; it can collide across sends).
      - `link_code_hash` string, nullable — The correlation key an event webhook quotes: 32 hex chars, 128 bits of SHA-256 over the full grant code. Match an interaction event to its receipt on THIS, never on `link_code`. Never the grant itself.
      - `link_type` string, nullable
      - `verification_level` 'none' | 'identifier' | 'passkey' | 'out_of_band' | 'dual_control' | 'null', nullable — The level the recipient satisfied. Wider than the set a send may ASK for: a grant minted under a retired level is still enforced at the strength it names, so a receipt can report one.
      - `action_hash` string, nullable — SHA-256 of the canonicalized action the identity acted on. Null on a plain view.
      - `signed_token` string, nullable — Ed25519 (EdDSA) JWT attesting the interaction. Verify against the account JWKS at https://auth.sparkvault.com/{account_id}/.well-known/jwks.json. Null on a view receipt.
      - `decision` string, nullable — Approve/decline outcome on an approval ceremony.
      - `thread_id` string, nullable
      - `reply_spark_id` string, nullable
      - `send_id` string, nullable — The send whose grant produced this receipt, stamped at mint time. Null for a standalone SparkLink, and for a receipt served from the legacy audit source.
      - `title` string, nullable — The send's display title, under the same conditions as send_id.
      - `receipt_id` string, nullable — The receipt row id. Null on the legacy source.
    - `cursor` string, nullable, required — Opaque continuation token. Null when the listing is exhausted.
    - `source` 'receipt_index' | 'legacy_scan', required — Which store answered. `legacy_scan` pages can be empty without being the end of the data.
  - `meta` ResponseMeta — Envelope metadata present on every successful response.
    - `api_version` string
    - `request_id` string
    - `response_ms` integer
    - `timestamp` integer — Unix seconds.
    - `pools` object — Storage and bandwidth capacity snapshot for the account.
    - `billing` object
      - `past_due` boolean
    - `quota` object — This minute of the account request budget. Present on authenticated success responses that passed the throttle; absent otherwise.
      - `limit` integer
      - `used` integer
      - `remaining` integer
      - `resets_at` integer — Unix seconds.

## Other responses

- `400` — VALIDATION_ERROR — the message names the offending field.
- `401` — AUTHENTICATION_ERROR — missing or invalid credentials.
- `403` — FORBIDDEN — the caller may not act on this account.
- `429` — RATE_LIMIT_EXCEEDED — the account exceeded 300 requests this minute. `Retry-After` carries the seconds to wait, and `details` carries limit/resets_at, plus `used` whenever the request was counted. A request refused because the limiter itself was unavailable reports no `used`.

---

[API](https://skmtc.dev/sparkvault/apis/sparkvault-api.md) · [All operations](https://skmtc.dev/sparkvault/apis/sparkvault-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/sparkvault/sparkvault-api/revisions/aaf3fd4981d9/schema)
