API Documentation

API Documentation

REST API for managing subscriptions programmatically. You can also download the OpenAPI spec.

Overview

Authentication

The API uses token authentication. Manage your tokens from the API tokens page.

Pass the token in the Authorization header on every request:

Authorization: Bearer {your-token}

Base URL

https://blogtrottr.com/api

All endpoints are relative to this base. Requests must include Accept: application/json.


Pagination

List responses are paginated at 100 items per page:

{
  "data": [ ... ],
  "links": {
    "first": "https://...",
    "last":  "https://...",
    "prev":  null,
    "next":  "https://...?page=2"
  },
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 100,
    "total": 250
  }
}

Use the page query parameter to navigate pages.


Field Reference

schedule

ValueDescription
asapReal-time — one email per new item
2h_digestDigest every 2 hours
4h_digestDigest every 4 hours
6h_digestDigest every 6 hours
8h_digestDigest every 8 hours
12h_digestDigest every 12 hours
daily_digestDaily digest

output

ValueDescription
emailStandard HTML email
attach_pdfEmail with PDF attachment
attach_htmlEmail with HTML attachment
attach_textEmail with plain text attachment
webhookHTTP webhook delivery

digest_sort

Only applicable when schedule is a digest type. Ignored for asap.

ValueDescription
newest_firstMost recent items at the top (default)
oldest_firstOldest items at the top
title_azSort by title A–Z
title_zaSort by title Z–A

Filter object

The filter field on subscriptions and categories is a structured content filter. When a filter is enabled, each incoming feed item is tested against it; items that do not pass are skipped.

Top-level structure

FieldTypeDescription
versionintegerMust be 2
enabledbooleanWhether the filter is active. Set to false to disable without removing the filter.
actionstringpermit — only deliver items that match. deny — skip items that match.
group_operatorstringHow to combine multiple groups: and or or
groupsarrayUp to 5 rule groups (see below)

Group

FieldTypeDescription
operatorstringHow to combine rules within the group: and or or
rulesarray1–250 rules. Total rules across all groups may not exceed 500.

Rule

FieldTypeDescription
fieldstringitem_title, item_body, item_url, author, category
operatorstringcontains, not_contains, regex, not_regex
valuestringMatch value, max 500 chars. For regex / not_regex: a PCRE pattern (no delimiters), max 200 chars, matched case-insensitively.

Example

Permit only items whose title contains "AI" or "machine learning":

{
  "version": 2,
  "enabled": true,
  "action": "permit",
  "group_operator": "or",
  "groups": [
    {
      "operator": "or",
      "rules": [
        { "field": "item_title", "operator": "contains", "value": "AI" },
        { "field": "item_title", "operator": "contains", "value": "machine learning" }
      ]
    }
  ]
}

JSON Schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["version", "enabled", "action", "group_operator", "groups"],
  "additionalProperties": false,
  "properties": {
    "version":        { "type": "integer", "const": 2 },
    "enabled":        { "type": "boolean" },
    "action":         { "type": "string", "enum": ["permit", "deny"] },
    "group_operator": { "type": "string", "enum": ["and", "or"] },
    "groups": {
      "type": "array",
      "maxItems": 5,
      "items": {
        "type": "object",
        "required": ["operator", "rules"],
        "additionalProperties": false,
        "properties": {
          "operator": { "type": "string", "enum": ["and", "or"] },
          "rules": {
            "type": "array",
            "minItems": 1,
            "maxItems": 250,
            "items": {
              "type": "object",
              "required": ["field", "operator", "value"],
              "additionalProperties": false,
              "properties": {
                "field":    { "type": "string", "enum": ["item_title", "item_body", "item_url", "author", "category"] },
                "operator": { "type": "string", "enum": ["contains", "not_contains", "regex", "not_regex"] },
                "value":    { "type": "string", "minLength": 1, "maxLength": 500 }
              }
            }
          }
        }
      }
    }
  }
}

Note: the 500-rule total limit across all groups and the 200-character cap on regex patterns cannot be expressed in JSON Schema and are enforced server-side.


Errors

All errors return JSON:

{
  "message": "The url field is required.",
  "errors": {
    "url": ["The url field is required."]
  }
}

Feed discovery failures return:

{
  "message": "Feed not found.",
  "details": { ... }
}

HTTP status codes

CodeMeaning
200OK
201Created
204No Content
401Unauthenticated — missing or invalid token
403Forbidden — token lacks required permission
404Not found
422Validation error

Subscriptions

List subscriptions

GET /api/subscriptions permission: read

Returns a paginated list of subscriptions.

Query parameters

ParameterTypeDescription
urlstringFilter by exact feed URL
enabledbooleanFilter by enabled state (true / false)
schedulestringFilter by schedule value (see Field Reference)
outputstringFilter by output type (see Field Reference)
category_idstring|nullFilter by category ID. Pass null to list uncategorised subscriptions.

Example response

{
  "data": [
    {
      "id": "aabbccddeeff001122334455",
      "enabled": true,
      "url": "https://example.com/feed.rss",
      "schedule": "asap",
      "output": "email",
      "digest_sort": null,
      "from": null,
      "subject_format": null,
      "title_only": false,
      "user_title": null,
      "filter": { "version": 2, "enabled": false, ... },
      "email_address_id": null,
      "created_at": "2024-01-15T10:30:00.000000Z",
      "updated_at": "2024-01-15T10:30:00.000000Z"
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Get subscription

GET /api/subscriptions/{id} permission: read

Returns a single subscription.

StatusMeaning
200Success
404Subscription not found

Create subscription

POST /api/subscriptions permission: create

Creates a new subscription. The feed URL will be discovered and normalised — if it resolves or redirects to a different URL than submitted, the final URL will be used.

Request body (JSON)

FieldRequiredTypeNotes
urlYesstring (URL)Feed URL, max 1000 chars. Must be unique per account.
scheduleYesstringSee Field Reference
outputYesstringSee Field Reference
digest_sortNostringDefault: newest_first. See Field Reference.
fromNostringCustom sender name, max 150 chars
subject_formatNostringCustom email subject template, max 150 chars
utitleNostringCustom subscription title, max 150 chars
titleonlyNobooleanSend item title only (no body)
email_address_idNostringID of an additional email address to deliver to
category_idNostring|nullID of a category to assign this subscription to
filterNoobjectContent filter rules object
webhook_urlIf output=webhookstring (URL)Webhook endpoint, max 2048 chars. Must be a public URL.
webhook_headersNoarrayUp to 10 custom headers. Each: {"key": "...", "value": "..."}
webhook_content_typeNostringapplication/json (default), application/x-www-form-urlencoded, text/plain
webhook_body_templateIf non-JSON webhookstringBody template for non-JSON webhooks, max 10000 chars

Example request

POST /api/subscriptions
Content-Type: application/json
Authorization: Bearer {token}

{
  "url": "https://example.com/feed.rss",
  "schedule": "asap",
  "output": "email"
}

Responses

StatusMeaning
201Subscription created. Returns the subscription object.
422Validation error (invalid fields, duplicate URL, plan limit reached, or feed not found)

Update subscription

PATCH /api/subscriptions/{id} permission: update

Partially updates a subscription. Only include the fields you want to change — all fields are optional.

Request body (JSON)

FieldTypeNotes
enabledbooleanEnable or pause the subscription
schedulestringSee Field Reference
outputstringSee Field Reference
digest_sortstringSee Field Reference
fromstring|nullCustom sender name
subject_formatstring|nullCustom email subject template
utitlestring|nullCustom subscription title
titleonlyboolean|nullSend item title only
email_address_idstring|nullAdditional delivery email address ID
category_idstring|nullCategory ID. Pass null to remove from a category.
filterobjectContent filter rules object
webhook_urlstring|nullWebhook endpoint
webhook_headersarray|nullCustom headers array
webhook_content_typestring|nullWebhook content type
webhook_body_templatestring|nullWebhook body template

Responses

StatusMeaning
200Updated. Returns the updated subscription object.
404Subscription not found
422Validation error

Delete subscription

DELETE /api/subscriptions/{id} permission: delete

Permanently deletes a subscription.

StatusMeaning
204Deleted successfully. No response body.
404Subscription not found

Email addresses

List email addresses

GET /api/email-addresses permission: read

Returns a paginated list of additional email addresses on the account. Use the id field as the email_address_id when creating or updating subscriptions.

Query parameters

ParameterTypeDescription
emailstringFilter by exact email address (case-insensitive)

Example response

{
  "data": [
    {
      "id": "aabbccddeeff001122334455",
      "email": "[email protected]",
      "enabled": true,
      "created_at": "2024-01-15T10:30:00.000000Z"
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Get email address

GET /api/email-addresses/{id} permission: read

Returns a single email address.

StatusMeaning
200Success
404Email address not found

Example response

{
  "data": {
    "id": "aabbccddeeff001122334455",
    "email": "[email protected]",
    "enabled": true,
    "created_at": "2024-01-15T10:30:00.000000Z"
  }
}

Categories

List categories

GET /api/categories permission: read

Returns a paginated list of the account's subscription categories, ordered by name.

Example response

{
  "data": [
    {
      "id": "aabbccddeeff001122334455",
      "name": "Tech",
      "filter": null,
      "created_at": "2024-01-15T10:30:00.000000Z",
      "updated_at": "2024-01-15T10:30:00.000000Z"
    }
  ],
  "links": { ... },
  "meta": { ... }
}

Get category

GET /api/categories/{id} permission: read

Returns a single category.

StatusMeaning
200Success
404Category not found

Create category

POST /api/categories permission: create

Request body (JSON)

FieldRequiredTypeNotes
nameYesstringCategory name, max 80 chars. Must be unique per account.
filterNoobject|nullContent filter rules object applied to all subscriptions in this category

Responses

StatusMeaning
201Category created. Returns the category object.
422Validation error (missing name, duplicate name)

Update category

PATCH /api/categories/{id} permission: update

Partially updates a category. Only include the fields you want to change.

Request body (JSON)

FieldTypeNotes
namestringCategory name, max 80 chars. Must be unique per account.
filterobject|nullContent filter rules. Pass null to remove.

Responses

StatusMeaning
200Updated. Returns the updated category object.
404Category not found
422Validation error

Delete category

DELETE /api/categories/{id} permission: delete

Permanently deletes a category. Any subscriptions assigned to it will have their category_id set to null.

StatusMeaning
204Deleted successfully. No response body.
404Category not found