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.