API reference

Offers

An offer is a document you send with a tracked link. anymail records when the recipient opens it, how long they read and how far they get. Offers are read-only in the API. The API returns metadata and statistics. The content of the document is not returned.

Method Path Action
GET /api/v1/offers List sent offers
GET /api/v1/offers/{id} Get an offer with its visits

List offers#

Parameter Type Notes
status string One of sent, opened, read. The API applies it to the fetched page. See Pagination.
prospect_id UUID Offers sent to one prospect.
campaign_id UUID Offers sent in one campaign.
limit integer 1 to 100. Default 50.
cursor string See Pagination.
curl "https://app.anymail.watch/api/v1/offers?status=read" \
  -H "Authorization: Bearer $ANYMAIL_TOKEN"

Response 200

{
  "data": [
    {
      "id": "9a1f0b2c-0000-4000-8000-000000000001",
      "prospect": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "email": "ada@example.com", "first_name": "Ada", "last_name": null },
      "company": { "id": "1b4e28ba-2fa1-11d2-883f-0016d3cca427", "name": "Example Ltd", "domain": "example.com" },
      "campaign": null,
      "document": { "format": "html_pasted", "label": "Proposal v2", "url": null, "path": "offers/example/proposal-v2.html" },
      "url": "https://app.seegnals.com/offer/Qm9…",
      "sent_at": "2026-09-01T10:00:00.000+00:00",
      "status": "opened",
      "visit_status": "returned",
      "visits": 2,
      "returns": 1,
      "total_active_seconds": 247,
      "progress": { "max_page_reached": 3, "total_pages": 6, "completed": false },
      "first_viewed_at": "2026-09-01T11:02:00.000+00:00",
      "last_viewed_at": "2026-09-02T09:15:00.000+00:00"
    }
  ],
  "next_cursor": null
}

Two status fields#

Field Values Answers
status sent, opened, read Did the recipient read it? read means they reached the end (completed) or the last known page.
visit_status sent, viewed, returned How many times did they come back? 0, 1, or 2 or more visits.
  • total_active_seconds is the sum over all visits.
  • progress.total_pages is null for a PDF without sections. For such a document completed is the only signal for read.
  • url is the public address of the offer, the one the app shows under Copy link. It uses the white-label host when the workspace sets one.
  • campaign is null when the offer was not sent from a campaign.

Errors: 400 for an invalid status, UUID, limit or cursor.

Get an offer#

GET /api/v1/offers/{id} returns the row above plus the visits and the reading time per page.

curl "https://app.anymail.watch/api/v1/offers/9a1f0b2c-0000-4000-8000-000000000001" \
  -H "Authorization: Bearer $ANYMAIL_TOKEN"

Response 200 (the fields of the list row are shortened)

{
  "id": "9a1f0b2c-0000-4000-8000-000000000001",
  "status": "opened",
  "visits": 2,
  "visit_list": [
    {
      "session_id": "s2",
      "started_at": "2026-09-02T09:15:00.000+00:00",
      "active_seconds": 40,
      "device": "iPhone · Safari",
      "max_page_reached": 3,
      "completed": false,
      "visit_index": 2
    },
    {
      "session_id": "s1",
      "started_at": "2026-09-01T11:02:00.000+00:00",
      "active_seconds": 207,
      "device": "Mac · Chrome",
      "max_page_reached": 2,
      "completed": false,
      "visit_index": 1
    }
  ],
  "pages": [
    { "id": "sec1", "position": 0, "label": "Intro", "page_type": "cover", "visits_read": 2, "total_active_seconds": 70, "last_read_at": "2026-09-02T09:16:00.000+00:00" },
    { "id": "sec2", "position": 1, "label": "Pricing", "page_type": "pricing", "visits_read": 1, "total_active_seconds": 30, "last_read_at": null }
  ]
}
  • visit_list holds up to the 200 latest visits, newest first. visit_index counts in time order, so 1 is the first visit.
  • device is approximate, for example Mac · Chrome, Unknown device or Automated client.
  • pages sums the reading time per page or section over all visits. It is empty for a PDF without sections.

Errors: 404 with {"error":"Offer not found."}.