Base URL

https://api.unisave.io/v1
For self-hosted instances, replace with your own domain.

Authentication

Most endpoints require a valid access token in the Authorization header:
Authorization: Bearer <accessToken>
Access tokens are short-lived JWTs. Use the refresh endpoint to obtain new ones.
Refresh tokens are passed in JSON request bodies only — never in headers or query strings.

Request Format

  • Content-Type: application/json for all request bodies
  • Timestamps: ISO 8601 / RFC 3339 in UTC (e.g., 2026-04-12T10:30:00Z)
  • IDs: Client-generated UUIDs for bookmarks and collections (clientBookmarkId, clientCollectionId)

Response Format

All 2xx responses return JSON objects. The shape varies by endpoint — see individual endpoint docs.

Error Envelope

All non-2xx responses use a consistent error envelope:
{
  "code": "error-code-string",
  "message": "Human-readable description",
  "requestId": "uuid-for-tracing"
}
The requestId is also returned in the X-Request-Id response header.

Error Codes

These are stable strings your client can match on for UX and retry decisions:
CodeHTTP StatusDescription
invalid-body400Malformed or missing request body fields
invalid-query400Invalid query string parameters
invalid-url400URL is not a valid http: or https: URL
unauthenticated401Missing or expired access token
forbidden403Insufficient permissions
pro-required403Feature requires a Pro subscription
not-found404Resource does not exist
method-not-allowed405HTTP method not supported for this path
conflict409Resource conflict (e.g., duplicate)
identity-already-in-use409OAuth identity linked to another account
quota-exceeded429Enrichment quota exhausted (free tier)
internal500Unexpected server error
not-configured501Feature not yet configured on this instance
timeout503Request processing timed out
Unknown error codes should be treated like internal — show a generic error and allow safe retry.

Rate Limiting

Auth endpoints (/v1/auth/*) are rate-limited to 2 requests/second sustained with a burst of 10 per IP. All authenticated endpoints have a 30-second timeout per request.

Endpoint Summary

AreaMethodPathAuthDescription
AuthPOST/auth/anonymousNoneCreate anonymous user
AuthPOST/auth/oauth/googleOptionalGoogle sign-in or link
AuthPOST/auth/oauth/appleOptionalApple sign-in or link
AuthPOST/auth/refreshNoneRotate tokens
AuthPOST/auth/logoutNoneRevoke refresh token
UserGET/meRequiredUser profile + Pro status
UserDELETE/accountRequiredDelete account
BookmarksGET/bookmarks/deltaRequiredDelta sync
BookmarksPUT/bookmarks/{id}RequiredUpsert bookmark
BookmarksDELETE/bookmarks/{id}RequiredSoft-delete
BookmarksPUT/bookmarks/{id}/collectionsRequiredSet collections
CollectionsGET/collections/deltaRequiredDelta sync
CollectionsPUT/collections/{id}RequiredUpsert collection
CollectionsDELETE/collections/{id}RequiredSoft-delete
EnrichmentPOST/enrichment/enqueueRequiredQueue enrichment
EnrichmentGET/enrichment/statusRequiredCheck status
SearchGET/search/bookmarksRequiredHybrid search
RecallGET/recallRequiredMemory recall (Pro)
SubscriptionsPOST/subscriptions/apple/verifyRequiredVerify Apple sub
SubscriptionsPOST/subscriptions/google/verifyRequiredVerify Google sub
OpsGET/healthzNoneHealth check