The enrichment API lets you trigger AI analysis of saved URLs and monitor job progress.

Enqueue Enrichment

Queue a bookmark for AI enrichment. The server validates the URL, checks quotas, and either returns a cached result or starts processing.
curl -X POST \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  "https://api.unisave.io/v1/enrichment/enqueue" \
  -d '{
    "clientBookmarkId": "abc-123",
    "url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
    "clientSavedAt": "2026-04-12T10:30:00Z"
  }'
Request Body
FieldTypeRequiredDescription
clientBookmarkIdstringYesMust match ^[a-zA-Z0-9_-]{1,128}$
urlstringYesValid http: or https: URL
clientSavedAtstringYesISO 8601 timestamp
Response — Cache Hit 200
{
  "cacheHit": true,
  "status": "completed"
}
When the normalized URL has been enriched before (by any user), the cached result is applied instantly — no job is created. Response — Queued 202
{
  "accepted": true,
  "status": "pending"
}
A new enrichment job is created. The bookmark will be updated asynchronously when processing completes.

Behavior Details

The enqueue endpoint performs these checks in order:
  1. URL validation — must be valid http:/https: scheme
  2. URL normalization — strips tracking params, fragments, www. prefix
  3. Cache lookup — if the normalized URL has cached results, applies them immediately
  4. Duplicate check — detects if the user already has this normalized URL
  5. Existing job check — skips if a pending/processing job already exists
  6. Quota check — enforces free-tier limits (see below)
  7. Job creation — creates the enrichment job with status pending
The useAi consent gate must be enabled for enrichment to proceed. If the user hasn’t consented to AI processing, the request is rejected.

Get Enrichment Status

Check the status of an enrichment job and retrieve results.
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://api.unisave.io/v1/enrichment/status?clientBookmarkId=abc-123"
Query Parameters
ParamTypeRequiredDescription
clientBookmarkIdstringYesThe bookmark to check
Response 200
{
  "data": {
    "clientBookmarkId": "abc-123",
    "status": "completed",
    "result": {
      "normalizedUrl": "https://youtube.com/watch?v=dQw4w9WgXcQ",
      "domain": "youtube.com",
      "title": "Rick Astley - Never Gonna Give You Up",
      "description": "The official video for Rick Astley's...",
      "thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
      "summary": "Rick Astley's iconic 1987 music video...",
      "saveWhy": "Classic music video reference",
      "tags": ["music", "video", "80s", "pop"],
      "snapshotStatus": "completed"
    },
    "errorCode": null
  }
}
FieldTypeDescription
clientBookmarkIdstringThe bookmark queried
statusstringJob status (see table below)
resultobject | nullEnrichment data when available. null while pending/processing.
errorCodestring | nullError code when enrichment fails. null on success.
The saveWhy field inside result is Pro-gated. Free users receive null for this field even when enrichment is complete. Upgrade to Pro to access it.

Status Values

StatusDescription
pendingJob created, waiting to be picked up by worker
processingWorker is actively fetching and analyzing the URL
retryingPrevious attempt failed, scheduled for retry
completedEnrichment finished successfully
failedAll retry attempts exhausted

Quotas

Free-tier users have enrichment quotas:
LimitFreePro
Per month200Unlimited
Per minute5Unlimited
When quota is exceeded, the API returns 429 quota-exceeded:
{
  "code": "quota-exceeded",
  "message": "Monthly enrichment limit reached. Upgrade to Pro for unlimited enrichments."
}
Monthly quota resets on the 1st of each month (UTC).

Retry Policy

Failed enrichments are retried automatically:
AttemptDelayCondition
1st retry1 minuteIf error is retriable
2nd retry5 minutesIf error is retriable
3rd failurePermanent failure
Retriable errors: network timeouts, DNS failures, HTTP 5xx, rate limits from content providers. Non-retriable errors: HTTP 4xx, blocked hosts, invalid URLs, quota exhausted.