User & Settings
Everything under /api/v1/user acts on the authenticated account. Three of these endpoints are
Pro-gated; the rest, including every export, work on any plan.
Get Current User
Section titled “Get Current User”GET /api/v1/user/me
Returns the profile, the current idea count, and trial state. Encrypted provider keys are
stripped and replaced by has_*_key booleans.
curl https://neuralrepo.com/api/v1/user/me \ -H "X-API-Key: nrp_YOUR_KEY"const res = await fetch("https://neuralrepo.com/api/v1/user/me", { headers: { "X-API-Key": "nrp_YOUR_KEY" },});const user = await res.json();Response 200 OK
{ "id": "3f2a91c47b0e4d5aa8c61e0f2b7d4c93", "email": "you@example.com", "display_name": "Jane Doe", "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4", "plan": "pro", "settings_json": "{\"preferred_ai_provider\":\"anthropic\"}", "has_anthropic_key": true, "has_openai_key": false, "has_openrouter_key": false, "trial_ends_at": "2026-04-01 00:00:00", "trial_used": 1, "active_idea_count": 137, "is_trialing": true, "trial_days_remaining": 6, "created_at": "2026-01-15 08:00:00", "updated_at": "2026-03-20 12:00:00"}| Field | Meaning |
|---|---|
plan | free or pro. Trialing accounts read pro — the gates treat them as Pro |
active_idea_count | Unarchived ideas; compare with 50 to see how close a Free account is to its cap |
is_trialing | true only when the plan is pro, the trial has not ended, and there is no Stripe subscription |
trial_days_remaining | Whole days, rounded up; null when not trialing |
email_capture_bare_optin | 1 if you opted in to the shared idea@ address for the transition, else 0. Your personal capture address is not in this response; see Email Capture Address |
Update Profile
Section titled “Update Profile”PATCH /api/v1/user/me
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | No | 1–100 characters |
settings_json | string | No | A JSON string, max 10,000 characters. See User Settings |
curl -X PATCH https://neuralrepo.com/api/v1/user/me \ -H "X-API-Key: nrp_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"display_name": "Jane D.", "settings_json": "{\"search_threshold\":0.3}"}'Response 200 OK — the updated user object, with the same stripped fields as GET /user/me
but without active_idea_count and the trial fields.
API Keys
Section titled “API Keys”List Keys
Section titled “List Keys”GET /api/v1/user/api-keys
Returns every key on the account, newest first, with no key material — not even a masked prefix.
Response 200 OK
{ "api_keys": [ { "id": "9c4f1b7e2d3a48f0b6e5c8d1a2f7b904", "label": "CI Pipeline", "scopes": null, "source": "manual", "last_used_at": "2026-03-24 08:12:00", "created_at": "2026-03-20 10:00:00" } ]}source is manual for keys made here and mcp for tokens minted by the MCP OAuth flow;
scopes is null on every manual key, which means full access.
Create Key
Section titled “Create Key”POST /api/v1/user/api-keys
| Field | Type | Required | Description |
|---|---|---|---|
label | string | No | Max 100 characters; defaults to default |
Response 201 Created
{ "id": "9c4f1b7e2d3a48f0b6e5c8d1a2f7b904", "key": "nrp_a1b2c3d4...", "label": "CI Pipeline", "created_at": "2026-03-24 09:00:00"}Delete Key
Section titled “Delete Key”DELETE /api/v1/user/api-keys/:id
Revokes the key immediately, using the id from the list endpoint (a 32-character hex string,
not the key itself). Works on every plan. Returns 404 if the id is not yours.
Response 200 OK
{ "success": true}MCP Tokens
Section titled “MCP Tokens”GET /api/v1/user/mcp-tokens
Lists the tokens issued by the MCP OAuth flow when you authorize a client such as Claude. It does not create tokens — the client does that during authorization.
Response 200 OK
{ "tokens": [ { "id": "b17d0e59a4c34f8e91d2c6b7f0a35e82", "label": "MCP (claude-ai)", "scopes": "ideas:read ideas:write", "source": "mcp", "last_used_at": "2026-03-24 08:00:00", "created_at": "2026-03-20 10:00:00" } ]}The client’s identity appears inside label; there is no separate client_id field. Revoke a
token with DELETE /api/v1/user/api-keys/:id — MCP tokens live in the same store as API keys.
Revoking one also revokes that client’s refresh tokens, so the client has to authorize again.
An MCP token stops working 30 days after it was issued. The client uses its refresh token to get a new one, and the refresh deletes the old token, so the list normally holds one token per connected client. The daily retention sweep removes tokens older than 30 days.
BYOK (Bring Your Own Key)
Section titled “BYOK (Bring Your Own Key)”AI features that run on your own provider account — POST /ideas/:id/develop in this API — need
a stored provider key. NeuralRepo encrypts it at rest and never returns it.
Save Provider Key
Section titled “Save Provider Key”PUT /api/v1/user/byok/:provider
Pro only. :provider must be anthropic, openai, or openrouter.
| Field | Type | Required | Description |
|---|---|---|---|
api_key | string | Yes | Your provider key; must be at least 10 characters |
curl -X PUT https://neuralrepo.com/api/v1/user/byok/anthropic \ -H "X-API-Key: nrp_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"api_key": "sk-ant-..."}'The key is stored without being tested — a typo is accepted here and fails later at
develop time. Run the test endpoint below to confirm it works.
Response 200 OK
{ "success": true, "provider": "anthropic"}Delete Provider Key
Section titled “Delete Provider Key”DELETE /api/v1/user/byok/:provider
Removes the stored key. Unlike saving and testing, this is not Pro-gated — an account that lapses to Free can still delete keys it stored while on Pro.
Response 200 OK
{ "success": true, "provider": "anthropic"}Test Provider Key
Section titled “Test Provider Key”POST /api/v1/user/byok/:provider/test
Pro only. Decrypts the stored key and makes a minimal live call to the provider.
curl -X POST https://neuralrepo.com/api/v1/user/byok/anthropic/test \ -H "X-API-Key: nrp_YOUR_KEY"Response 200 OK
{ "ok": true}A failure is also 200, with the reason in the body: { "ok": false, "error": "No anthropic key configured" }
when nothing is stored, or the provider’s own message when the call is rejected. Check ok,
not the status code.
Check All Providers
Section titled “Check All Providers”GET /api/v1/user/byok/status
Returns which providers have keys and which one will actually be used.
Response 200 OK
{ "active_provider": "anthropic", "has_anthropic_key": true, "has_openai_key": false, "has_openrouter_key": false}active_provider resolves as: your preferred_ai_provider setting if a key for it is
stored, otherwise the first available in the fixed order Anthropic → OpenAI → OpenRouter. It is
null when no keys are stored — which is when develop returns needs_byok. Setting a
preference for a provider you have no key for is silently ignored rather than erroring.
Shortcuts
Section titled “Shortcuts”GET /api/v1/user/shortcuts
Returns the iCloud Shortcut URL used for Siri capture. The same URL for every account.
curl https://neuralrepo.com/api/v1/user/shortcuts \ -H "X-API-Key: nrp_YOUR_KEY"Response 200 OK
{ "quick_capture_url": "https://www.icloud.com/shortcuts/..."}Support Link
Section titled “Support Link”GET /api/v1/user/support-link
Mints a single-use, pre-authenticated URL into the NeuralRepo support site for the account’s email address, so you arrive already signed in.
Response 200 OK
{ "url": "https://support.neuralrepo.com/..."}Returns 502 { "error": "Failed to generate support link" } if the support service is
unreachable. Treat the URL as a credential — anyone holding it is signed in as you.
Test Digest
Section titled “Test Digest”POST /api/v1/user/test-digest
Sends the weekly digest email to your own address immediately, and returns the rendered content so you can preview it without waiting for Sunday.
curl -X POST https://neuralrepo.com/api/v1/user/test-digest \ -H "X-API-Key: nrp_YOUR_KEY"Response 200 OK
{ "success": true, "content": "..."}If sending fails, the endpoint returns 500 with the underlying error message.
User Settings
Section titled “User Settings”settings_json is a JSON string on the profile. Values outside the stated ranges are discarded
when the settings are parsed, and the default applies instead — nothing reports the mistake.
| Field | Type | Range | Default | Description |
|---|---|---|---|---|
preferred_ai_provider | string | anthropic, openai, openrouter | — | Provider for develop, if a key for it is stored |
search_threshold | number | 0.1–0.9 | 0.2 | Semantic results must score above this |
dedup_threshold | number | 0.1–0.9 | 0.75 | Score above which a pair is flagged as a duplicate |
related_threshold | number | 0.1–0.9 | 0.55 | Score above which a related edge is created automatically |
code_mode | boolean | — | — | Exposes the MCP code-mode tool surface |
weekly_digest | boolean | — | opted in | Only an explicit false stops the Sunday digest |
stale_nudges | boolean | — | opted in | Only an explicit false stops stale-idea nudge emails |
stale_threshold_days | integer | 7–180 | 30 | Days before a captured idea counts as stale |
Data Export
Section titled “Data Export”Export is available on every plan, and all three endpoints are POST with no body. Each
covers up to 10,000 ideas and excludes archived ideas — export before you archive, not after.
JSON Export
Section titled “JSON Export”POST /api/v1/user/export
The complete dump: profile, ideas with their tags, links, and relations, plus the tag list with
counts. Returned as a JSON body (not a file download), stamped with exported_at.
curl -X POST https://neuralrepo.com/api/v1/user/export \ -H "X-API-Key: nrp_YOUR_KEY" \ -o export.jsonCSV Export
Section titled “CSV Export”POST /api/v1/user/export/csv
A flat table for spreadsheets: id, number, title, body, status, tags (semicolon
separated), source, created_at. Sent as a UTF-8 BOM’d text/csv attachment named
neuralrepo-ideas-YYYY-MM-DD.csv. Relations and links are not included.
curl -X POST https://neuralrepo.com/api/v1/user/export/csv \ -H "X-API-Key: nrp_YOUR_KEY" \ -o export.csvMarkdown Export
Section titled “Markdown Export”POST /api/v1/user/export/markdown
A ZIP of one Markdown file per idea, named NNNN-slug.md from the idea’s display number and
title. Each file carries YAML frontmatter (number, title, status, source, tags,
created, updated), the body, a Links section, and a Related section where relations become
[[wiki-links]] — so an Obsidian vault reproduces your mind map graph.
curl -X POST https://neuralrepo.com/api/v1/user/export/markdown \ -H "X-API-Key: nrp_YOUR_KEY" \ -o neuralrepo-markdown.zipEmail Capture Address
Section titled “Email Capture Address”The personal idea+<token>@neuralrepo.com address that
email capture delivers to. These routes work on every plan, but
mail is captured only on Pro.
| Endpoint | Does |
|---|---|
GET /api/v1/user/email-capture | Returns your address, creating it on the first call |
POST /api/v1/user/email-capture/rotate | Replaces the address. The old one is rejected from then on |
PUT /api/v1/user/email-capture/bare-address | Body { "opt_in": true } or { "opt_in": false }: opts in to, or out of, the shared idea@ address until the cut-off |
All three return the same shape:
{ "address": "idea+3f9c0a1b2c3d4e5f6a7b8c9d@neuralrepo.com", "bare_address": "idea@neuralrepo.com", "bare_address_opt_in": false, "bare_address_open": true, "bare_address_sunset": "2026-10-24T00:00:00Z"}| Field | Meaning |
|---|---|
address | Your personal capture address. Treat it as a secret: anyone who has it can add ideas to your repo |
bare_address_opt_in | Whether mail from your account email to idea@ is still captured |
bare_address_open | false once bare_address_sunset has passed; after that idea@ rejects everything |
bare_address_sunset | When the shared address stops capturing |
PUT /bare-address returns 400 opt_in (boolean) is required for a missing or non-boolean
opt_in, and 409 The shared address has been retired; use your personal capture address
for opt_in: true after the cut-off. Opting out always works.
Delete Account
Section titled “Delete Account”DELETE /api/v1/user/me
Deletes the account and everything it owns. Delete Data
lists what is removed, what is kept, and what is out of reach. Web session only: an API key
or MCP token gets 403.
Request body:
{ "confirm_email": "you@example.com" }confirm_email must match the account’s email, ignoring letter case and surrounding spaces.
Response 200 OK: { "success": true, ... }, with counts of what was deleted
(rows, vectors_deleted, kv_keys_deleted), whether a subscription was canceled
(subscription_canceled), and the out_of_reach list. The session cookie is cleared.
| Status | Body error |
|---|---|
400 | confirm_email is required, or The email you typed does not match your account |
403 | Sign in on the web to delete your account, or The admin account cannot be deleted here |
404 | User not found |
502 | Account deletion did not finish. You are still signed in; try again to complete it. Nothing past the failed step was deleted, and a retry continues |
Status Codes
Section titled “Status Codes”| Status | Meaning |
|---|---|
200 OK | Successful read, update, delete, account deletion, or export |
201 Created | API key created |
400 Bad Request | Validation error, or an unknown BYOK provider |
401 Unauthorized | Missing or invalid auth |
403 Forbidden | Pro-only endpoint on a Free plan (pro_required: true), or account deletion without a web session or on the admin account |
404 Not Found | API key id not yours, or the user record is missing |
409 Conflict | Opting in to the shared idea@ address after its cut-off |
500 Internal Server Error | test-digest failed to send |
502 Bad Gateway | The support service could not mint a link, or account deletion did not finish |