Overview
The Narrative Lion API lets you programmatically access your notes, run searches, submit jobs, chat with AI, and more. Use it with Claude Code, Cursor, or any AI agent that speaks HTTP.
Base URL
https://api.narrativelion.comMost read/write operations are available via GraphQL at POST /graphql. Billing, audio streaming, and file exports use dedicated REST endpoints. Chat uses SSE.
AI Agent Skill
Already using Claude Code, Cursor, Codex, or another AI agent? Install the Narrative Lion skill so your agent knows how to call this API for you.
npx skills add rayjan0114/narrative-lion-skillsAuto-detects your AI tool and installs to the right location. Run the same command anytime to pull the latest version.
After install, set your API key in your shell:
export NL_API_KEY=nlk_your_api_key_hereAuthentication
All API requests require an API key sent as a Bearer token in the Authorization header.
curl https://api.narrativelion.com/api/export/jobs \
-H "Authorization: Bearer nlk_your_api_key_here"API keys are available on the Pro and Business plans. Create one in Settings → API Keys.
Each key has a set of scopes that control what it can access. Keys are prefixed with nlk_ for easy identification.
REST Endpoints
REST endpoints handle billing, binary streaming, and file operations that are not suited for GraphQL.
/api/billing/usageGet current billing period usage and credit balance.
{
"tier": "pro",
"period": "month",
"resetsAt": "2026-05-21T00:00:00.000Z",
"credits": {
"used": 20,
"limit": 3600,
"remaining": 3580
},
"wallet": {
"balance": 0,
"enabled": false
}
}/api/audio/:noteId/:segmentIdStream a podcast audio segment for a note.
| Name | Type | Required | Description |
|---|---|---|---|
noteId | string | Required | Note ID |
segmentId | string | Required | Segment ID |
Returns an audio stream (audio/mpeg).
/api/export/requestRequest a Markdown export of all your notes. Returns a job ID for polling.
curl -X POST https://api.narrativelion.com/api/export/request \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{"format": "markdown"}'/api/export/jobsList your export jobs and their status.
{
"jobs": [
{
"id": "job-456",
"status": "completed",
"format": "markdown",
"createdAt": "2026-04-20T10:00:00.000Z"
}
]
}/api/export/download/:jobIdDownload a completed export as a zip file.
Returns the file as application/zip.
GraphQL
The GraphQL endpoint is at POST /graphql. Send a JSON body with query and optional variables.
curl https://api.narrativelion.com/graphql \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"query": "{ me { id email name } }"
}'Queries
List jobs
query {
jobs(status: queued, limit: 10) {
id
url
status
createdAt
}
}Get your notes
query {
myNotes(limit: 20) {
id
videoId
noteType
lang
noteMd
tags
updatedAt
}
}Get a single note
query {
note(noteId: "abc-123") {
id
videoId
noteType
lang
title
noteMd
tags
starredAt
createdAt
updatedAt
}
}Get a note with raw transcript
query {
note(noteId: "abc-123") {
id
noteMd
transcriptAvailable
transcriptBytes
rawTranscript # only fetched when selected
}
}rawTranscript is lazy — it only triggers a storage fetch when explicitly selected. For cheap metadata-only queries, use transcriptAvailable and transcriptBytes to check availability first. Transcripts are only available for video notes that have finished processing.
Browse notes with filters
query {
browseNotes(noteType: "video", starred: true, sort: "updated", limit: 10) {
id
noteMd
starredAt
tags
}
}Search notes (semantic)
query {
search(query: "machine learning fundamentals", limit: 5) {
id
videoId
title
noteMd
score
}
}Full-text search
query {
ftsSearch(query: "transformer architecture", limit: 10) {
id
videoId
noteType
snippet
rank
}
}Mutations
Submit a YouTube video for note generation
mutation {
submitJob(url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ") {
id
status
createdAt
}
}Create a general note
mutation {
createGeneralNote(content: "# My Notes\n\nSome content here...") {
id
noteMd
createdAt
}
}Update a note
mutation {
updateNote(noteId: "abc-123", noteMd: "# Updated content") {
id
version
updatedAt
}
}Delete a note
mutation {
deleteNote(noteId: "abc-123")
}Star / unstar a note
mutation {
toggleStar(noteId: "abc-123") {
id
starredAt
}
}Manage tags
mutation {
addTag(noteId: "abc-123", tag: "important") {
id
tags
}
}SSE Streaming
The chat endpoint uses Server-Sent Events (SSE) for streaming responses. Send a POST request and read the event stream.
/api/chat/streamStart a streaming chat session.
curl -N https://api.narrativelion.com/api/chat/stream \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"threadId": "thread-uuid",
"actionId": "action-uuid",
"event": {
"type": "user_text",
"payload": { "text": "Summarize my latest note" }
}
}'| Name | Type | Required | Description |
|---|---|---|---|
threadId | string | Required | Chat thread ID (UUID). Create a new one per conversation. |
actionId | string | Required | Unique action ID (UUID) for idempotency. |
event.type | string | Required | "user_text", "interview_answer", or "edit_note" |
event.payload | object | Required | Event-specific data. For user_text: { text: string } |
Event stream format
event: token
data: {"t":"Hello"}
event: token
data: {"t":" world"}
event: complete
data: {"messageId":"msg-123","usage":{"inputTokens":150,"outputTokens":42}}| Event | Description |
|---|---|
token | Incremental text token from the model |
complete | Stream finished. Includes message ID and usage stats. |
error | An error occurred during generation |
Scopes
Each API key has a set of scopes that determine what operations it can perform. When creating a key, choose a preset or customize individual scopes.
| Scope | Preset | Access |
|---|---|---|
notes:read | Read | Read notes, browse, get note by ID |
notes:write | Standard | Create, update, star, tag notes |
notes:delete | - | Delete notes |
search | Read | Semantic search and full-text search |
jobs:read | Read | View job status |
jobs:submit | Standard | Submit YouTube URLs for note generation |
chat | Standard | Chat with AI (SSE streaming) |
podcast | Standard | Generate podcast audio |
export | Standard | Request and download exports |
billing:read | Read | View usage and credit balance |
Read preset includes: notes:read, search, jobs:read, billing:read.
Standard preset includes all Read scopes plus: notes:write, jobs:submit, chat, podcast, export.
Error Codes
The API returns errors as JSON with an error field and an optional code field.
{
"error": "Credit limit reached (120/100). Resets 2026-05-21",
"code": "QUOTA_EXCEEDED"
}| HTTP | Code | Description |
|---|---|---|
401 | TOKEN_MISSING | No API key provided |
401 | TOKEN_INVALID | Invalid or revoked API key |
401 | TOKEN_EXPIRED | API key has expired |
403 | - | Scope not sufficient, or plan downgraded below Pro |
429 | RATE_LIMITED | Too many requests |
402 | QUOTA_EXCEEDED | Credit limit reached for this billing period |
Rate Limits
Rate limits are applied per account. If you exceed the limit, the API returns a 429 status.
| Endpoint | Limit |
|---|---|
| Chat | 5 requests / 10 seconds |
| Search | 20 requests / 60 seconds |
| Mutations (write operations) | 30 requests / 60 seconds |
| Job submission | 10 jobs / minute per account |