Skip to main content
Developers · Push API

Push custom data into Pulse.

Any system without a native connector can pump documents into Pulse via a single POST. The doc lands in search, Decision Memory extraction, commitment extraction, and the F4 sensitivity scanner without any extra wiring.

EndpointPOST /v1/documents

Bearer token from /app/admin/api-keys with thewrite scope. Demo workspaces reject pushed docs with a 403.

Request body
  • title (required, string, max 280 chars)
  • body (required, string, max 200,000 chars)
  • url? canonical URL of the source doc
  • authorName? human-readable author name
  • externalId? stable id from your source system; defaults to a UUID
  • idempotencyKey? client-supplied key. Retrying with the same key is safe (see Idempotency)
  • metadata? freeform JSON, stored alongside the doc for downstream filtering
  • visibility? "tenant" (default) or "private"
cURL
curl -X POST https://api.pulse.app/v1/documents \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q3 OKRs",
    "body": "Our Q3 priorities...",
    "url": "https://internal.trellis.com/okrs/q3",
    "authorName": "Therese Linden",
    "idempotencyKey": "okrs-q3-v1"
  }'
Python
import requests, os

resp = requests.post(
    "https://api.pulse.app/v1/documents",
    headers={"Authorization": f"Bearer {os.environ['PULSE_API_KEY']}"},
    json={
        "title": "Q3 OKRs",
        "body": open("okrs-q3.md").read(),
        "url": "https://internal.trellis.com/okrs/q3",
        "idempotencyKey": "okrs-q3-v1",
    },
    timeout=30,
)
resp.raise_for_status()
print(resp.json())  # { "data": { "id": "doc_abc...", "status": "queued" } }
Idempotency
  • 200Retrying with the same idempotencyKey and the same body returns the original id with "status": "duplicate".
  • 409Same idempotencyKey with a different body fails with idempotency_conflict. Use a new key.
  • Without an idempotency key, every retry creates a new doc. Strongly recommended for production integrations.
What happens after the 200

Pulse runs the doc through the same pipeline as native connectors:

  • Embed: chunked + vectorized for hybrid retrieval (~10-30s).
  • Summarize: 1-line summary surfaces in Ask citation chips and the doc list.
  • Decision extraction: if the doc records a decision, it lands in Decision Memory.
  • Commitment extraction: any “X will do Y by Z” gets surfaced as a commitment.
  • Sensitivity classification: regex + Haiku classifier flags credentials, NDA-marked content, revenue forecasts before the daily cron.
Visibility & permissions

By default pushed docs are visible to the entire tenant (matching how a Notion page or Google Doc would behave on a typical connector). Set"visibility": "private"to scope the doc to the user who owns the API key · the doc is ACL-restricted to that user only and won’t surface in others’ Ask answers.

Limits
  • Body field: 200,000 characters (≈40,000 words).
  • Request body total: 256 KB.
  • Per-key push cap: 5,000 docs per day (separate from the 100/min · 10,000/day shared key limit).
  • 429 responses include a Retry-After header.
Error codes
  • 401 unauthorized · missing or invalid bearer.
  • 403 insufficient_scope · key lacks the write scope.
  • 403 demo_disabled · workspace is a demo tenant.
  • 409 idempotency_conflict · same key, different body.
  • 413 payload_too_large · request body over 256 KB.
  • 422 validation_failed / invalid_json.
  • 429 rate_limited / ingest_quota_exceeded.
See the REST API overview for the full GET surface and webhook subscriptions. Need bulk ingest, file upload, or an SDK? Tell us what you need.