# Foluro API v1

Base URL: `https://foluro.com/api/v1` (or your own Foluro origin).
Create a workspace API key in Dashboard → Integrations. Include `Authorization: Bearer YOUR_KEY` on every request. Never put a key into a public page, browser script, URL or published catalog. Keys expire after 90 days; revoke a key from the same screen.

Read-only keys can access all published and draft catalogs, leads and link events within their workspace. A write-enabled key can also create and publish catalogs. Rate limit: 120 requests per minute per key; remote PDF imports: 10 per hour. Normal storage limits still apply.

| Method | Path | Result |
| --- | --- | --- |
| GET | /catalogs | Catalog array (published and draft); optional `q` title search and exact `slug` filter |
| GET | /catalogs/:id | Catalog, products, draft, versions and publication settings |
| POST | /catalogs | Multipart fields `file` (PDF) and `title`; creates a private draft |
| POST | /catalogs/import | JSON `{"url":"https://…/file.pdf","title":"My catalog"}`; creates a private draft |
| POST | /catalogs/:id/publish | Publish the current draft at its stable link |
| POST | /catalogs/:id/unpublish | Remove public access |
| GET | /leads | Paginated lead submissions, including skipped submissions |
| GET | /tracking-events | Paginated tracked-link opens |

## Polling without losing events

`/leads` and `/tracking-events` return `{items, hasMore, nextCursor}` in ascending event order, up to 100 rows. The first request can use `?since=2026-09-10T00%3A00%3A00.000Z`. Save `nextCursor` after processing every item, then request `?cursor=...`. When `hasMore` is true, continue immediately. When false, keep the same cursor and poll again later. Deduplicate by `id`; process retries idempotently. Events with equal timestamps are ordered by ID. Events arriving late with an older timestamp are not supported; Foluro timestamps inserts at ingestion.

To trigger on new catalogs, poll `/catalogs`, deduplicate by catalog `id`, and compare `created_at` if needed. Find a catalog by ID, slug extracted from its publication URL, or title query.

## PDF URL imports

Only publicly accessible HTTPS addresses on port 443 are accepted. Private/reserved IP ranges and credential-bearing URLs are rejected, including redirect destinations. DNS addresses are pinned for the connection. Up to three redirects; 25 MB PDF maximum for remote URL imports; up to 2,000 pages. Files must be actual valid, unencrypted PDFs. No authenticated private drive URLs. Imported files remain drafts until you explicitly publish them.

## Errors and access

Errors use an HTTP status and `{error: "message"}`. Typical statuses: 400 invalid input, 401 invalid/expired key, 403 read-only key or forbidden action, 404 unknown/out-of-workspace catalog, 409 conflicting edit, 413 size limit, 429 rate limit. Retry transient failures with backoff. A successful import is not idempotent: save its returned ID before retrying. If a request times out after upload, check `/catalogs` before importing again.

## Automation providers

These endpoints can be used with HTTP modules in Make/n8n or a private Zapier integration. No Foluro app is currently listed in those marketplaces. This release uses polling; outbound webhooks and marketplace OAuth are not yet available. Email queue delivery requires a configured SMTP sender and a running mail worker.

## Plans and upload limits

Direct multipart PDF uploads follow workspace limits: Starter 250 MB, Growth 500 MB, Pro and Business 1 GB. PDFs may contain up to 2,000 pages. All saved PDF versions and uploaded media count toward one storage allowance. `GET /api/workspaces/:id/plan` (session authentication) reports live usage. Requests to change plans do not activate subscriptions or change allowances.
