API Reference
Base URL: https://usekosu.com/api/v1
All endpoints require a Bearer token. See Authentication.
A note on pagination
Queue items use cursor-based pagination because the queue is drag-reorderable – cursors stay stable as items move. All other states (read, archived, deleted, suggested) use offset-based pagination, sorted by last updated.
Items
Items are URLs in a user's queue.
/itemsAdd a URL to the queue. Kosu canonicalizes the URL, fetches metadata, and deduplicates. If the URL already exists as an active item, returns it unchanged. If archived/read/deleted, reactivates it.
| Name | Type | Required | Description |
|---|---|---|---|
url | string | Yes | URL to add (1-2048 chars). Kosu fetches metadata automatically. |
title | string | No | Override auto-fetched title (1-256 chars). |
source | string | No | Override content type. One of: youtube, podcast, paper, newsletter, repo, article, book, course, other. |
thumbnail | string | No | Override thumbnail URL. |
channel_name | string | No | Creator or channel name. |
duration_minutes | integer | No | Duration in minutes (0-99999). |
curl -X POST https://usekosu.com/api/v1/items \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'{
"object": "item",
"id": "itm_abc123",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"source": "youtube",
"state": "queue",
"channel_name": "Rick Astley",
"thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
"duration": "3m 33s",
"duration_minutes": 3,
"created_at": "2026-02-25T10:00:00.000Z",
"updated_at": "2026-02-25T10:00:00.000Z",
"opened_at": null,
"read_at": null,
"archived_at": null,
"meta": {
"created": true,
"reactivated": false
}
}Returns 201 if created or reactivated, 200 if already in queue. Check meta.created and meta.reactivated to distinguish.
/itemsList items filtered by state. Defaults to queue items.
| Name | Type | Required | Description |
|---|---|---|---|
state | string | No | Filter by state: queue (default), read, archived, deleted, suggested. |
limit | integer | No | Max items to return. 1-100, default 50. |
cursor | string | No | Pagination cursor (queue state only). Use next_cursor from previous response. |
offset | integer | No | Pagination offset (non-queue states only). |
curl https://usekosu.com/api/v1/items?state=queue&limit=10 \
-H "Authorization: Bearer YOUR_API_KEY"{
"object": "list",
"data": [
{
"object": "item",
"id": "itm_abc123",
"url": "https://example.com/article",
"title": "Example Article",
"source": "article",
"state": "queue",
"channel_name": null,
"thumbnail": null,
"duration": null,
"duration_minutes": null,
"created_at": "2026-02-25T10:00:00.000Z",
"updated_at": "2026-02-25T10:00:00.000Z",
"opened_at": null,
"read_at": null,
"archived_at": null
}
],
"has_more": false,
"next_cursor": null
}/items/:idFetch a single item by ID.
curl https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"/items/:idUpdate an item. Send exactly one of four update types in the request body.
State transition
Move an item to a new lifecycle state.
| Name | Type | Required | Description |
|---|---|---|---|
state | string | Yes | Target state: read, archived, queue (requeue), or suggested (Pro). |
reason | string | No | Reason for suggesting (only when state is suggested, max 512 chars). |
# Mark as read
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"state": "read"}'
# Archive
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"state": "archived"}'
# Requeue (restore to bottom of queue)
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"state": "queue"}'Record open
Mark the item as opened. This is a passive touch – it extends fade protection by 1 day (max once per 24 hours).
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"opened": true}'Reorder
Move an item to a new position using relative positioning. Provide after and/or before to specify placement.
| Name | Type | Required | Description |
|---|---|---|---|
position.after | string | null | No | Place after this item ID. null = move to top. |
position.before | string | null | No | Place before this item ID. null = move to bottom. |
# Move to top of queue
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"position": {"after": null}}'
# Place after another item
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"position": {"after": "itm_other456"}}'Field update
Update metadata fields. At least one field required.
| Name | Type | Required | Description |
|---|---|---|---|
title | string | No | Item title (1-256 chars). |
source | string | No | Content type. |
thumbnail | string | No | Thumbnail URL. |
channel_name | string | No | Creator or channel name. |
duration_minutes | integer | No | Duration in minutes. |
curl -X PATCH https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Better Title", "source": "paper"}'/items/:idSoft-delete an item. Moves to deleted state, recoverable for 30 days. Idempotent.
curl -X DELETE https://usekosu.com/api/v1/items/itm_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"{
"object": "item",
"id": "itm_abc123",
"state": "deleted",
"deleted": true
}Suggestions
Suggest content for a user's review. The user sees suggestions in a separate tab and can accept (move to queue) or dismiss them. Pro feature.
/suggestionsSuggest a URL. If the URL is already active in the queue, returns 409. If previously suggested, updates the existing suggestion.
| Name | Type | Required | Description |
|---|---|---|---|
url | string | Yes | URL to suggest (1-2048 chars). |
reason | string | No | Why you're suggesting this. Shown to the user (1-512 chars). |
title | string | No | Override title (1-256 chars). |
source | string | No | Override content type. |
thumbnail | string | No | Override thumbnail URL. |
channel_name | string | No | Creator or channel name. |
duration_minutes | integer | No | Duration in minutes. |
curl -X POST https://usekosu.com/api/v1/suggestions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/distributed-systems-guide",
"reason": "Relevant to your interest in distributed systems"
}'{
"object": "suggestion",
"id": "sug_def456",
"url": "https://example.com/distributed-systems-guide",
"title": "A Guide to Distributed Systems",
"source": "article",
"channel_name": null,
"thumbnail": null,
"duration": null,
"duration_minutes": null,
"reason": "Relevant to your interest in distributed systems",
"created_at": "2026-02-25T12:00:00.000Z",
"updated_at": "2026-02-25T12:00:00.000Z"
}Returns 201 if created, 200 if updated, 409 if URL is already an active item.
/suggestionsList active suggestions.
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Max suggestions to return. 1-100, default 50. |
curl https://usekosu.com/api/v1/suggestions \
-H "Authorization: Bearer YOUR_API_KEY"/suggestions/:idAccept or dismiss a suggestion. Accept moves it to the queue. Dismiss soft-deletes it.
| Name | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Either "accept" or "dismiss". |
# Accept a suggestion
curl -X POST https://usekosu.com/api/v1/suggestions/sug_def456 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"action": "accept"}'
# Dismiss a suggestion
curl -X POST https://usekosu.com/api/v1/suggestions/sug_def456 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"action": "dismiss"}'Accept returns an Item object. Dismiss returns {"object": "suggestion", "id": "sug_...", "dismissed": true}.
Object reference
Item
| Name | Type | Required | Description |
|---|---|---|---|
object | "item" | Yes | Object type. |
id | string | Yes | Prefixed ID (e.g. "itm_abc123"). |
url | string | null | Yes | Canonical URL. |
title | string | null | Yes | Title. |
source | string | Yes | Content type. |
state | string | Yes | Lifecycle state: queue, suggested, read, archived, deleted. |
channel_name | string | null | No | Creator or channel. |
thumbnail | string | null | No | Thumbnail URL. |
duration | string | null | No | Human-readable duration (e.g. "1h 30m"). |
duration_minutes | integer | null | No | Duration in minutes. |
created_at | string | Yes | ISO 8601 timestamp. |
updated_at | string | Yes | ISO 8601 timestamp. |
opened_at | string | null | No | First opened timestamp. |
read_at | string | null | No | Marked read timestamp. |
archived_at | string | null | No | Archived timestamp. |
Suggestion
| Name | Type | Required | Description |
|---|---|---|---|
object | "suggestion" | Yes | Object type. |
id | string | Yes | Prefixed ID (e.g. "sug_abc123"). |
url | string | null | Yes | Canonical URL. |
title | string | null | Yes | Title. |
source | string | Yes | Content type. |
channel_name | string | null | No | Creator or channel. |
thumbnail | string | null | No | Thumbnail URL. |
duration | string | null | No | Human-readable duration. |
duration_minutes | integer | null | No | Duration in minutes. |
reason | string | null | No | Why this was suggested. |
created_at | string | Yes | ISO 8601 timestamp. |
updated_at | string | Yes | ISO 8601 timestamp. |
List
| Name | Type | Required | Description |
|---|---|---|---|
object | "list" | Yes | Object type. |
data | array | Yes | Array of Item or Suggestion objects. |
has_more | boolean | Yes | Whether more results exist. |
next_cursor | string | null | Yes | Cursor for next page (queue state only). |
Error
| Name | Type | Required | Description |
|---|---|---|---|
error.type | string | Yes | Error category. |
error.code | string | Yes | Machine-readable error code. |
error.message | string | Yes | Human-readable description. |
error.param | string | No | The field that caused the error. |
© 2026 Kosu