API reference

A versioned REST API over the same org-scoped data you see in the app. Base URL https://api.pulserie.com/api/v1. All responses are JSON.

Authentication

Every request needs an API key sent as a bearer token. Create one under Settings, API keys (Pro and Business plans). Keys start with plsr_ and are shown in full only once.

http
Authorization: Bearer plsr_your_api_key

A missing or invalid key returns 401. If your plan does not include API access the request returns 402.

Rate limits

Limits are per organization, per minute. Exceeding a limit returns 429; slow down and retry.

  • Pro60 requests / min
  • Business300 requests / min

Errors

Errors use the shape { "error": "...", "reason"?: "..." } with a matching HTTP status.

401 Unauthorized

json
{ "error": "unauthorized" }

402 Plan limit

json
{ "error": "plan_limit", "reason": "api_access" }

429 Rate limited

json
{ "error": "rate_limited" }

Sites

A site is one seed URL Pulserie crawls on a schedule. Modes are page (watch a single page) or list (track items across a listing).

  • GET/sites
    List sites
  • POST/sites
    Create a site
  • GET/sites/:id
    Get one site
  • PATCH/sites/:id
    Update a site
  • DELETE/sites/:id
    Delete a site
  • POST/sites/:id/crawl
    Trigger a crawl now
  • GET/sites/:id/pages
    List crawled pages

List sites

bash
curl https://api.pulserie.com/api/v1/sites \
  -H "Authorization: Bearer plsr_your_api_key"

Create a site

Body: name and seedUrl are required; mode and maxPages are optional.

bash
curl -X POST https://api.pulserie.com/api/v1/sites \
  -H "Authorization: Bearer plsr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme pricing","seedUrl":"https://acme.com/pricing","mode":"list","maxPages":25}'
javascript
const res = await fetch("https://api.pulserie.com/api/v1/sites", {
  method: "POST",
  headers: {
    Authorization: "Bearer plsr_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Acme pricing",
    seedUrl: "https://acme.com/pricing",
    mode: "list",
    maxPages: 25,
  }),
});
const site = await res.json();

Returns the created site:

json
{
  "id": "site_8fk2p",
  "name": "Acme pricing",
  "seedUrl": "https://acme.com/pricing",
  "mode": "list",
  "maxPages": 25,
  "intervalMinutes": 1440,
  "lastCrawledAt": null,
  "createdAt": "2026-07-02T09:12:00.000Z"
}

Fields

Fields are named values Pulserie extracts and tracks over time on a site, such as a plan price or a headline. kind may be text or number; numeric fields get a value history and trend.

  • GET/sites/:id/fields
    List a site's fields
  • POST/sites/:id/fields
    Add a field
  • DELETE/fields/:id
    Delete a field
  • GET/fields/:id/values
    Field value history

Add a field

javascript
const res = await fetch(
  "https://api.pulserie.com/api/v1/sites/site_8fk2p/fields",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer plsr_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Pro plan price",
      description: "Monthly price of the Pro tier in EUR",
      kind: "number",
    }),
  },
);
const field = await res.json();

Field value history

bash
curl https://api.pulserie.com/api/v1/fields/field_31ab/values \
  -H "Authorization: Bearer plsr_your_api_key"

Newest first. Numeric fields include a parsed numericValue.

json
[
  { "value": "29", "numericValue": 29, "observedAt": "2026-07-01T06:00:00.000Z" },
  { "value": "25", "numericValue": 25, "observedAt": "2026-06-01T06:00:00.000Z" }
]

Changes

A change is a detected, AI-filtered difference on a site, with a summary and a screenshot. Filter by siteId or read a single change by id.

  • GET/changes
    List changes (optional ?siteId=)
  • GET/changes/:id
    Get one change

List changes

bash
curl "https://api.pulserie.com/api/v1/changes?siteId=site_8fk2p" \
  -H "Authorization: Bearer plsr_your_api_key"
javascript
const url = new URL("https://api.pulserie.com/api/v1/changes");
url.searchParams.set("siteId", "site_8fk2p");

const res = await fetch(url, {
  headers: { Authorization: "Bearer plsr_your_api_key" },
});
const changes = await res.json();

Returns matching changes, newest first:

json
[
  {
    "id": "chg_9d2",
    "siteId": "site_8fk2p",
    "url": "https://acme.com/pricing",
    "summary": "Pro plan price increased from EUR 25 to EUR 29 per month.",
    "screenshotUrl": "https://cdn.pulserie.com/shots/chg_9d2.webp",
    "createdAt": "2026-07-01T06:00:00.000Z"
  }
]