NEURVONAGet started

DEVELOPER DOCS · API V1 · VERSION 4.2.0

Build with your persona.

Use REST from your app or MCP from your agent. Generate private X drafts, manage background sources, and control the account owner’s autopilot.

  1. Sign in and create an API key. Use X if you’ll manage a persona or autopilot. Google-only accounts can generate drafts.
  2. Set NEURVONA_API_KEY in your server environment.
  3. Send your first request. Read account status for free. Add credits before starting AI work.
First request · cURL
curl --fail-with-body https://neurvona.ai/api/v1/posts \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-first-post-001" \
  -d '{"goal":"Share practical lessons about building useful products","count":1}'

Base URL: https://neurvona.ai/api/v1. OpenAPI 3.1 · Agent reference · Agent skill

Connect an AI agent

Add a remote server in any MCP client that supports Streamable HTTP and custom authorization headers. Configure the key as a secret in the client, rather than pasting it into a conversation. Client configuration formats vary; these are the connection values:

MCP server settings
Server URL: https://neurvona.ai/api/mcp
Transport: Streamable HTTP
Authentication header: Authorization: Bearer <your Neurvona API key>

The server offers 43 tools, listed in the endpoint table below. Tool annotations identify read-only operations and changes that can affect publishing. Account ownership, usage limits, and credit charges are the same as REST.

Raw protocol example
1 · Initialize
curl --fail-with-body https://neurvona.ai/api/mcp \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
    "protocolVersion":"2025-11-25",
    "capabilities":{},
    "clientInfo":{"name":"my-agent","version":"1.0.0"}
  }}'

Send notifications/initialized next with the negotiated version header. It returns HTTP 202 with an empty body:

2 · Initialization notification
{"jsonrpc":"2.0","method":"notifications/initialized"}

Use tools/list to discover schemas, then call a tool:

3 · Generate a private draft
curl --fail-with-body https://neurvona.ai/api/mcp \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
    "name":"generate_posts",
    "arguments":{
      "goal":"Share practical product-building lessons",
      "count":1,
      "idempotencyKey":"my-agent-post-001"
    }
  }}'

Supported protocol versions: 2025-11-25, 2025-06-18, and 2025-03-26. The server is stateless and returns JSON. No session ID is required. GET and DELETE return 405 because persistent SSE streams aren’t offered.

Successful calls return text JSON and, for newer protocol versions, structuredContent. Check isError before using a result. Execution errors contain error.code, error.status, and error.message; rate-limit errors also include retryAfterSeconds. Protocol errors use JSON-RPC codes.

Email, Google and promotion each have tools split by risk (for example draft_email, send_email and delete_email) with accurate annotations and an output schema; control_email_twin, control_google_workspace and control_boosts remain as deprecated names. An approval_required error carries the approval URL to give the owner. MCP resources: neurvona://guide and neurvona://openapi. Authentication uses an API key. OAuth discovery and clients that require OAuth-only authentication are not supported by this endpoint.

Authentication and ownership

Required on every authenticated request
Authorization: Bearer <NEURVONA_API_KEY>

Production keys begin with nv_live_. nv_test_ keys exist only outside production, on deployments without live Stripe keys. Keys are shown once, stored as hashes, and revocable in the console. Use a separate key per integration, with only the permissions it needs.

Scopes. Every key reads. Choose any of drafts (missions, imports, drafts, paid writing including email research, sources and settings), send (Gmail sending and Google Calendar and Docs changes), autopilot (X autopilot and promotion) and spend (paid persona research, media, voice and token quotes). An operation outside a key’s scopes answers 403 insufficient_scope, and MCP lists only the tools a key can use. New keys default to read and drafts, expire after 90 days (or 7, 30 or 365) and may charge at most 20 credits in a rolling day unless you choose another limit (409 key_spending_limit). Keys created before scopes are legacy keys with every scope: replace them.

Your approval. consent:true is the key’s request, never your authorization. Sending email, deleting a batch, Google changes, resuming or loosening autopilot, promotion, enabled sources, voice setup, X live and paid jobs over 5 credits answer 403 approval_required with error.approval.url. You open it while signed in and see exactly what the key asked for; once you approve, the same request goes through once within an hour, with its revisions checked again. Pausing and stopping never wait.

Keep keys in a secret manager or server environment. Never include them in client-side code, URLs, logs, or public repositories. Connect Google, X and other accounts to one shared twin in Autopilot. A connection whose account is another Neurvona account’s sign-in combines the two only after you review the other account and what would move, and never while both hold connected services; a mailbox another account connected without signing in with it never combines accounts, so disconnect it there first. Names or matching email addresses alone do not merge accounts. Google sign-in stays profile-only, with optional tool permissions requested separately, and connecting Gmail or Google sources adds a Google sign-in only when you choose it.

Read GET /me before acting. Authentication failures return 401 and WWW-Authenticate: Bearer. Authenticated responses are not cached. Browser sessions cannot substitute for an API key.

Google tools: one connection

Choose Gmail, Calendar, Docs and optional background sources in Google tools. Connect only the services you need; ordinary Google sign-in remains profile-only. API keys can use the granted tools but cannot perform OAuth for the owner.

GET /google returns selected services and private action history. POST /google/read reads calendars, events or a document selected by ID and changes nothing; calendar windows are bounded to 90 days. POST /google/prepare saves a private preview of a Calendar or Docs change, cancels a pending preview, or imports background sources that stay off until reviewed. POST /google/apply makes a prepared change (confirm) or removes the Google grant (disconnect). Document tools read, create, append or replace exact text in the first tab; they do not change sharing permissions.

POST /google/prepare · a private Google Doc, no Google write yet
{
  "action": "prepare",
  "id": "8744395d-11cc-4f34-b843-d6593960fca1",
  "data": {
    "action": "create_document",
    "title": "Project plan",
    "text": "The exact content to review."
  }
}

Show the complete returned operation to the owner, then send action: confirm with the same id and consent: true to POST /google/apply. Through an API key it answers 403 approval_required with error.approval.url: the owner opens it while signed in and approves this exact preview, and the same request then goes through once within an hour. Reviews expire after ten minutes, or an hour after the owner approves, and check the Google account, permissions and twin purpose. Edits also check the reviewed document revision or event version. Calendar invites and changes display any recipients Google will notify. An uncertain result must be checked in Google before preparing another request; retrying the same operation never repeats its write.

MCP exposes get_google_workspace, read_google_workspace, prepare_google_workspace and apply_google_workspace; POST /google and control_google_workspace remain as deprecated names that take every action. The same tools work through the twin conversation and paired text messages. Reading and manual changes are free; AI writing uses the displayed credit price. Imports remain inactive until approved in Your information. The OpenAPI contract contains every read/write field.

REST ↔ MCP reference

RESTMCP toolPurpose
GET /googleget_google_workspaceRead connected Google tools and recent change previews
POST /googlecontrol_google_workspaceRead Calendar/Docs, prepare a change, or confirm a reviewed change
POST /google/readread_google_workspaceRead calendars, events or a supplied document
POST /google/prepareprepare_google_workspacePrepare a private preview of a change, cancel it, or import background sources
POST /google/applyapply_google_workspaceMake an owner-approved Google change, or disconnect Google tools
GET /email/contactsget_email_contactsBrowse private contacts and confirmed outreach status
GET /emailget_email_twinRead email missions, drafts, inbox, activity, connection permissions and credits
POST /emailcontrol_email_twinCreate missions, import and edit drafts, prepare replies, approve selected sends or pause
POST /email/draftsdraft_emailWrite and manage drafts, missions, imports and research; never sends
POST /email/sendsend_emailSend owner-approved email, pause, suppress, or check an uncertain send
POST /email/deletedelete_emailPermanently delete unsent email
GET /tokenget_token_marketRead NEURVONA price, exact mint, bonus and checkout availability
POST /credits/tokencreate_token_checkoutQuote a prepaid NEURVONA credit purchase
GET /credits/token/{id}get_token_checkoutRead your saved token quote and confirmation state
POST /credits/token/{id}/transactionbuild_token_transactionBuild an unsigned Solana mainnet Token-2022 transaction
POST /credits/token/{id}/verifyverify_token_checkoutVerify a finalized payment and issue credits exactly once
GET /meget_accountRead your account and API credit balance
POST /postsgenerate_postsGenerate private X drafts
GET /missionget_twin_missionRead the owner’s shared twin mission
PATCH /missionupdate_twin_missionSave one mission across all enabled services
GET /autopilotget_autopilotRead autopilot status and setup requirements
PATCH /autopilotupdate_autopilotUpdate X writing notes, topics, pace, or timezone
POST /autopilot/pausepause_autopilotPause new autopilot posts
POST /autopilot/resumeresume_autopilotResume automatic posting with consent
GET /activityget_activityRead recent autopilot activity
GET /persona/photoREST onlyRead your private twin photo or its metadata
PUT /persona/photoREST onlySet your twin’s profile photo
DELETE /persona/photoREST onlyReturn to your X/default profile photo
GET /persona/sourcesget_persona_sourcesRead your private persona sources
POST /persona/sourcessave_persona_sourceCreate or update a source
DELETE /persona/sourcesremove_persona_sourceRemove a source from future writing
GET /persona/connectionsget_persona_connectionsList imported service connections and available scopes
POST /persona/connectionsupdate_persona_connectionRefresh an authorized import or disconnect a service
GET /persona/capabilitiesget_persona_capabilitiesRead availability, current prepaid prices, and limits
GET /persona/voiceget_persona_voiceRead your saved voice and setup price, or get words to record
POST /persona/voiceREST onlyCreate your personal voice from the owner reading their script
DELETE /persona/voiceremove_persona_voiceRemove your saved voice from future calls and request provider deletion
GET /persona/avatarsget_persona_avatarsList your video twins
DELETE /persona/avatarsremove_persona_avatarRemove a video twin and delete it at Anam
GET /persona/jobslist_persona_jobsList the 30 newest owner-scoped requests
POST /persona/jobscreate_persona_jobResearch the owner or start prepaid LiveKit media
GET /persona/jobs/{id}get_persona_jobRead a result or get a short-lived owner LiveKit token
DELETE /persona/jobs/{id}stop_persona_jobStop a live session or recording
GET /persona/jobs/{id}/fileREST onlyDownload or preview your private completed MP3 or MP4
HEAD /persona/jobs/{id}/fileREST onlyRead private recording type and size without downloading
POST /persona/transcriptionsREST onlyUpload raw audio/video bytes and save a reviewable transcript
GET /boostsget_boostsRead boost access, credits, and spending limits
POST /boostscontrol_boostsSave limits, preview, enable, approve, pause, or request access
POST /boosts/settingsconfigure_boostsSave limits, pause, or request or withdraw promotion access
POST /boosts/spendspend_boostsRun AI selection, or enable or start owner-approved promotion

All REST paths above are relative to /api/v1. Complete response schemas, operation IDs, constraints, and error responses are in OpenAPI.

Generate private drafts

POST /posts returns 1–5 drafts. Nothing publishes. Delivered drafts are validated for length and exclude links, hashtags, and mentions. The requested count is a maximum: unusable output is filtered. A request the provider refused costs nothing, unreadable output costs the provider’s measured cost, and only an attempt whose outcome is unknown keeps its reservation.

FieldTypeMeaning
goalstring · required3–500 characters. What the posts should work toward.
voicestringUp to 500 characters describing the voice.
topicsstring[]Up to 5 topics, each 1–60 characters.
factsstringUp to 2,000 characters of grounded facts.
countinteger1–5. Defaults to 1.
useMyProfilebooleanUse the saved twin profile and enabled persona sources. Defaults to false. Requires a saved X persona; returns 409 no_profile when none exists.
Example response
{
  "id": "gen_example",
  "posts": [{"text": "A useful product starts with one problem worth solving."}],
  "usage": {"posts": 1, "freePosts": 0, "chargedCents": 20},
  "replayed": false,
  "credits": {"balanceCents": 980, "freeRemaining": 0}
}
JavaScript example
Node.js
// Node.js 22+. Keep this key on your server.
const idempotencyKey = crypto.randomUUID(); // Save this for retries.
const response = await fetch("https://neurvona.ai/api/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NEURVONA_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": idempotencyKey,
  },
  body: JSON.stringify({
    goal: "Share practical lessons about building useful products",
    count: 1,
  }),
  signal: AbortSignal.timeout(60_000),
});
const result = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${result.error.message}`);
console.log(result.posts);
Python example
Python · no dependencies
# Python 3.10+. Standard library only.
import json, os, uuid
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request_id = str(uuid.uuid4())  # Save this for retries.
request = Request(
    "https://neurvona.ai/api/v1/posts",
    data=json.dumps({
        "goal": "Share practical lessons about building useful products",
        "count": 1,
    }).encode(),
    headers={
        "Authorization": "Bearer " + os.environ["NEURVONA_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": request_id,
    },
)
try:
    with urlopen(request, timeout=60) as response:
        print(json.load(response)["posts"])
except HTTPError as error:
    problem = json.load(error)
    raise RuntimeError(f"{error.code}: {problem['error']['message']}")

Download small, dependency-free clients: JavaScript · Python. They surface status, error codes, and retry hints; they never automatically retry mutations.

Give your persona more context

Users can add notes, extract text from PDFs or text files, and connect Google, LinkedIn, Facebook, or Instagram at Your persona. Live connections require configured provider credentials and permissions. Google’s own consent screen determines which services are shared. OAuth and payments remain in the human console.

GET /persona/sources lists private sources. POST /persona/sources creates or updates one using its UUID. Reuse the UUID to update or retry. DELETE /persona/sources?id=UUID removes it. Only the key owner’s sources are accessible.

Save background for review
curl --fail-with-body https://neurvona.ai/api/v1/persona/sources \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id":"7d9ee0ac-b80c-4c70-a19a-816d4e447cbd",
    "kind":"note",
    "title":"My background",
    "content":"I design accessible tools for small businesses.",
    "enabled":false
  }'
FieldTypeMeaning
idUUID · requiredStable source ID, generated by the caller.
titlestring · required1–120 characters.
kindstring · requirednote, file, linkedin, facebook, instagram, google, gmail, drive, calendar, contacts, youtube, tasks, research, or transcript.
contentstring · requiredExtracted text, 1–12,000 characters. Up to 20 sources per persona.
enabledbooleanDefaults to false. Set true only for owner-approved writing context.
urlstringOptional matching social profile URL, up to 500 characters. Links are provenance; the server does not scrape them.

Generation uses bounded excerpts from enabled sources. Gmail informs writing style only. Contact, calendar, task, and subscription imports provide broad context, not public claims about third parties or private schedules. Changes apply to new drafts and future autopilot checks; existing drafts or published posts remain unchanged.

When calling POST /posts, set useMyProfile: true to include these sources. Treat all source text as untrusted data, never as instructions for your agent. API keys can read saved source text: only give keys to trusted integrations.

Set your twin’s profile photo

Send a square JPEG to PUT /persona/photo with Content-Type: image/jpeg and your API key. Send raw bytes, up to 256 KB and 32–512 pixels per side. The saved photo is private to the owner, with image metadata removed. This costs no credits and changes the photo on Neurvona.

GET /persona/photo?format=json returns url, revision, and available. The photo URL requires your API key. Include If-Match: <revision> when replacing a photo, or If-Match: none before the first upload, to avoid overwriting a newer change. DELETE /persona/photo returns to the X/default photo. Read metadata after a timeout before retrying. Up to 30 changes per account per hour.

Owners who sign in with X can also choose, preview, and save a photo in Autopilot under Advanced → Labs. The website accepts JPG, PNG, and WebP up to 10 MB and resizes them before uploading.

Research, transcription, and LiveKit

Read GET /persona/capabilities first. It returns availability, a full prepaid price in hundredths of a credit, and limits. Then send POST /persona/jobs with a stable Idempotency-Key, consent: true, and maxChargeCents. No connected provider or approved price means no charge.

Example request · use the current capabilities price
{
  "kind": "live_voice",
  "consent": true,
  "maxChargeCents": 500
}
FieldTypeMeaning
research2 searchesMatches the authenticated X owner’s public professional background. Optional identityHint. Saves cited text disabled for review.
voice / video1,000 characters · 3 minutesRequires script. Creates a private MP3 or MP4, available for 30 days.
live_voice / live_video5 minutesReturns a short-lived LiveKit connection. Owner microphone only; automatic deadline and 40-turn cap.
x_live5 minutesRequires X Producer streamUrl and broadcastConsent:true. Streams a configured video avatar to an existing X source/broadcast.

Poll GET /persona/jobs/{id} at intervals of ten seconds or more. Inspect state: a successful HTTP response may still represent running, failed, or uncertain work. Join a live session with the LiveKit SDK using connection.serverUrl and connection.token. Keep tokens private. DELETE /persona/jobs/{id} ends live media; it does not refund work already started.

Your saved voice is selected automatically. Set voiceMode: personal to require it, or voiceMode: default for an audio-only Grok Eve call. Video always requires your saved personal voice. Get microphone permission before creating a paid call, then connect immediately. Only one live call can be active per owner. A second request returns 409 active_call without charging; retrieve the existing job for a fresh token to rejoin. Reconnecting does not extend the prepaid deadline. Show LiveKit’s listening, thinking, and speaking status, and provide a tap-to-enable sound button when browser playback is blocked.

Video uses your connected X profile photo with Anam inside LiveKit. Send useXPhoto: true and photoAttestation: true once the owner confirms that their X profile photo shows them and that they are 18 or older; their video twin records that attestation. Through an API key, a video job whose video twin the owner has not attested to answers approval_required until they approve it while signed in. First-time photo creation is included in the quoted call price. GET /persona/avatars lists the owner’s video twins and DELETE /persona/avatars?id=... removes one, at Anam too. The X stream option does not create or start a broadcast using ordinary X OAuth; the owner needs Media Studio Producer access.

Broadcast your twin on X

Owner setup is at the live studio. Create an RTMP source in X Producer and use its secure RTMPS URL plus stream key. Send kind: x_live, useXPhoto: true, photoAttestation: true, voiceMode: personal, streamUrl, and broadcastConsent: true, along with the current maximum price and stable idempotency key. An optional script (up to 1,000 characters) becomes an opening line after the AI disclosure.

Join the returned room immediately. The owner microphone is part of the stream. Poll job.broadcast.state: connecting, sending, ended, or failed. Sending confirms RTMPS delivery; the owner still creates the Public or Private broadcast on X. Never label a stream public based on this status. X viewer comments are not imported. The five-minute deadline and explicit stop close the room and egress; failures do not retry paid work. MCP uses the same create_persona_job, get_persona_job, and stop_persona_job tools. Keep stream URLs, keys, and connection tokens out of logs.

  1. In X Producer: Sources → Create source → RTMP. Select a region near the owner and copy the RTMPS URL and key.
  2. Get microphone permission, create the prepaid Neurvona job, and join its LiveKit room.
  3. In Producer: Create broadcast → choose the source → Public → Start immediately. Wait for video, then Create broadcast. Private is available for testing.
  4. Click Post beneath the broadcast preview to share it on X. End stream in Neurvona when finished; manage the replay in X.

Producer access and final X publishing remain controlled by X. Users without Producer can generate a downloadable MP4 and attach it to a normal post. Official X instructions.

Server example: create and control a broadcast
JavaScript · Neurvona client
// Run on your server with the owner's approval.
const {job} = await api.startJob({
  kind: 'x_live', consent: true, useXPhoto: true, photoAttestation: true, voiceMode: 'personal',
  maxChargeCents: approvedMaximum, // compare with capabilities first
  streamUrl: process.env.X_PRODUCER_RTMPS_URL, // includes the secret stream key
  broadcastConsent: true,
  script: 'Welcome! Here is what I have been working on.',
}, stableRequestId);
// Inspect job.state. Pass connection only to the authenticated owner client.
// Join immediately with LiveKit's client SDK. Never expose the Neurvona API key.
// Poll api.job(job.id) every 10 seconds for broadcast.state.
// Stop with await api.stopJob(job.id). No automatic renewal or paid retry.
Owner client: join with LiveKit
Browser · livekit-client
// Owner's browser, using livekit-client. Get mic permission BEFORE the
// server creates a paid job. Obtain job through your authenticated backend.
import {Room, RoomEvent, createLocalAudioTrack} from 'livekit-client';
const microphone = await createLocalAudioTrack();
// Now ask your server to create/retrieve the approved x_live job.
const room = new Room();
room.on(RoomEvent.TrackSubscribed, track => {
  const element = track.attach();
  element.setAttribute('playsinline', 'true');
  document.querySelector('#twin-media').appendChild(element);
});
try {
  await room.connect(job.connection.serverUrl, job.connection.token);
  await room.localParticipant.publishTrack(microphone);
  // Offer a tap-to-enable button if browser playback is blocked.
  await Promise.all([room.startAudio(), room.startVideo()]);
} catch (error) {
  microphone.stop();
  // Retrieve this job for a fresh token to rejoin without another charge.
  // Alternatively stop it through your server; never create a replacement automatically.
  throw error;
}
// End control: stop the job on your server, stop the mic, disconnect the room.
// Muting the room microphone also mutes your voice in the X feed.

Make a video to download

Use Make a video or create a video job. Supply an approved script, up to 1,000 characters, voiceMode: personal, useXPhoto: true and photoAttestation: true. The owner’s X photo and saved voice produce a private 720p H.264/AAC MP4. Every clip starts with the spoken words “This is an AI-generated clip.” before the script. The recording ends within three minutes and works without a microphone connection, browser tab, or X Producer access. Use kind: voice for an MP3.

Read capabilities, approve the credit ceiling, create once, and poll every ten seconds. Download only when state: complete and downloadPath is present. Authenticate the file request with the same owner API key. downloadExpiresAt is a Unix timestamp in milliseconds; downloads expire 30 days after creation. Files stay private and are never posted automatically. Keep a local copy before expiry.

Complete JavaScript example: script to MP4
Node.js 22+ · no LiveKit client needed
// Node.js 22+. Download neurvona.mjs from /developers/neurvona.mjs.
// The owner must first connect X, save their voice, and buy credits, and confirm that
// their X profile photo shows them and that they are 18 or older (photoAttestation).
import {readFile, writeFile} from 'node:fs/promises';
import {setTimeout as wait} from 'node:timers/promises';
import {Neurvona} from './neurvona.mjs';

const api = new Neurvona(); // NEURVONA_API_KEY, kept server-side
const idempotencyKey = process.env.NEURVONA_REQUEST_ID;
const maxChargeCents = Number(process.env.NEURVONA_MAX_CHARGE_CENTS);
if (!idempotencyKey || !Number.isSafeInteger(maxChargeCents) || maxChargeCents < 1)
  throw new Error('Set a stable request ID and an owner-approved credit ceiling.');

const {services} = await api.capabilities();
const video = services.find(service => service.kind === 'video');
if (!video?.available || video.priceCents > maxChargeCents)
  throw new Error('Video is unavailable or exceeds the approved price.');

// Persist this exact input and request ID before sending it.
// After a timeout, reuse both. A new ID can buy a second recording.
const input = {
  kind: 'video', consent: true, useXPhoto: true, photoAttestation: true, voiceMode: 'personal',
  script: (await readFile('script.txt', 'utf8')).trim(), maxChargeCents,
};
// Through a key, a first video twin answers approval_required: the owner approves it signed in.
let {job} = await api.startJob(input, idempotencyKey);
console.log('Recording request:', job.id);
const deadline = Date.now() + 10 * 60_000;
while (['starting', 'running', 'stopping'].includes(job.state) && Date.now() < deadline) {
  await wait(10_000);
  ({job} = await api.job(job.id));
}
if (job.state !== 'complete' || !job.downloadPath)
  throw new Error(job.id + ': ' + job.note + ' Inspect this job; do not buy another automatically.');
await writeFile('my-twin.mp4', Buffer.from(await api.recording(job.id)), {mode: 0o600});
console.log('Saved my-twin.mp4. Nothing was posted.');

The file endpoint also supports HEAD, single byte Range requests, and ?inline=1 for authenticated playback. Success is 200 or 206; invalid ranges return 416. A download URL alone grants no access. Do not put API keys in video URLs; stream through your authenticated backend.

MCP sequence: get_persona_capabilities → create_persona_job with the same video fields and idempotencyKey → get_persona_job → authenticated REST download. Use stop_persona_job to stop work early; started work is still charged. No binary data is embedded in MCP responses.

Record a personal voice

Users read words Neurvona chooses aloud, listen back, and approve saving their own voice on Neurvona. Read GET /persona/voice for setup availability, price, and saved voice status. Recording and retakes are free; saving a voice is a separate prepaid setup. Calls continue to use their quoted credits.

Get words with GET /persona/voice?script=new: the owner reads setup.script.text aloud, all in one recording, ending with eight random check words, and setup.script.token goes back with it. With explicit owner consent, send raw audio/wav bytes to POST /persona/voice?voiceConsent=true&maxChargeCents=N&script=TOKEN with a stable Idempotency-Key; it waits for the owner’s approval, which shows the words. Use a canonical 44-byte WAV header with mono, 24 kHz, 16-bit PCM, 10–45 seconds, at most 2,160,044 bytes. Use the owner’s actual recording; never synthesize or substitute another person’s voice. After reserving the price, Neurvona checks with speech-to-text that the recording says those words and little else: one that does not ends failed with chargedCents: 0 and never reaches Cartesia.

Wait for voice.state: ready before creating a personal call. If setup is uncertain, poll GET every ten seconds; never submit another key. The original provider attempt is reconciled. DELETE /persona/voice?id=... removes the saved voice; end active media first. Neurvona stores consent and metadata, while Cartesia stores the private voice. MCP offers get_persona_voice (with script: true for the words) and remove_persona_voice; upload audio through binary REST.

Turn uploaded video into persona text

Read capabilities inputFormat first. For pcm16-wav, send mono 16 kHz, 16-bit PCM WAV of at most 600 seconds with Content-Type: audio/wav. The Neurvona uploader prepares this locally from supported recordings; raw clients must prepare the same bounded audio themselves. Send bytes to POST /persona/transcriptions?maxChargeCents=N&consent=true&title=Interview with a stable Idempotency-Key. No multipart or base64 JSON. The limit is 25 MB. The optional AssemblyAI adapter accepts the previous audio/video formats. Invalid audio is rejected before charging. Reuse the same key after a lost response; uncertain provider work never repeats automatically. Poll the returned job and approve the resulting text source before using it.

Use authenticated GET /persona/jobs/{id}/file to download completed media. Binary transfers use REST; MCP handles prices, starts, results, and stops. GET /persona/jobs lists the newest 30 requests. No media provider is enabled without its configured credentials, prepaid rates, and caps.

Control autopilot

First, the human signs in with X, adds credits, and allows posting in X autopilot. API keys cannot grant OAuth permissions or sign wallet payments. The owner can authorize an agent to save settings and start autopilot through the API.

GET /autopilot includes enabled, available, connected, hasPlan, emailVerified, requirements, setupUrl, the goal, pace, timezone, next check, and usage. Requirements name setup steps; the final resume call still enforces explicit consent and service capacity.

FieldTypeMeaning
missionstringOne of job, clients, product, funding, reputation, sales, dating, community, custom.
briefstringYour goal in your words, up to 2,000 characters.
factsstringPublic facts, up to 3,000 characters.
topicsstring[]Up to 5 topics of 1–60 characters. [] disables reposts and quote comments.
postsPerDayinteger1–3, within the 93-action calendar-month limit.
creditDailyLimitCentsinteger0–10,000. Maximum in a rolling 24 hours; each check costs 60 cents.
headsUpEmailbooleanOptional. true requires verified email and gives a five-minute review window. false allows immediate posting.
timezonestringAn IANA timezone, such as America/Los_Angeles.

PATCH accepts one or more fields. A running autopilot keeps running after a change that only tightens it: fewer posts, a lower credit limit, the review email on, or topics: [] to stop reposts. Raising a limit, turning the review email off, turning reposts on, or changing the brief, facts or topics answers 403 approval_required, and nothing is saved until the owner approves that exact change while signed in; then send the same request again within an hour. Reposts stay as saved unless the request sends topics. A paused autopilot stays paused. Changing settings affects future public posts.

Pause automatic posting
curl --fail-with-body -X POST https://neurvona.ai/api/v1/autopilot/pause \
  -H "Authorization: Bearer $NEURVONA_API_KEY"

POST /autopilot/resume requires {"consent":true}, then answers 403 approval_required until the owner approves the saved settings while signed in; send it again within an hour of their approval. Pausing stops new posts; a dispatched post may still finish. Pausing doesn’t cancel billing or pause advertising.

GET /activity?limit=20 returns up to 30 recent actions, newest first. There is no pagination. Read type and reason before assuming a post was published.

Boost posts with Neurvona credits

Writing, autopilot, media, AI selection, and approved paid promotion use one Neurvona credit balance. Packs: $10 for 10 credits, $25 for 28 credits, $50 for 60 credits, $100 for 125 credits. Bonus credits count toward the balance; credit units are not dollars. Plans: Plus: $20/month or $200/year, 20 credits each month; Pro: $50/month or $500/year, 55 credits each month; Max: $200/month or $2000/year, 225 credits each month. Included credits renew monthly without rollover, including on annual billing. Extra purchased credits never expire. Upgrade or add extras after using your allowance; no automatic overage purchases.

2 credits fund $1 of X media, including campaign management. AI selection costs 0.40 credits per fresh check, at most 1.60 credits per rolling 24 hours. Checks and boosts both count toward the saved total and UTC daily credit limits. One test reserves up to 5 credits for up to $2.50 of media. Unused reserved credits return after X’s 14-day billing adjustment window and verified final billing.

Neurvona pays X through its own Ads account. Customers do not need X Money or their own Ads account. X must approve their handles as promotable users. Normal X login is not that approval. Ads require settled USD proceeds, net of payment fees, refunds, and other provider commitments. Card settlement can take several business days. Token-funded credits remain usable for AI; unsold tokens do not fund USD advertising.

  1. Read GET /boosts: settings, revision, eligibility, shared balance, readyCents, prices, and activity.
  2. Save settings with POST /boosts/settings, action save. Amount fields are hundredths of a credit. Saving is free and pauses existing boosts.
  3. Send action preview or enable to POST /boosts/spend with the current revision, consent:true, and pricingVersion:"shared-credits-v1". Through an API key, enable answers 403 approval_required until the owner approves while signed in; send it again within an hour of their approval.
  4. In review mode, action approve on POST /boosts/spend also needs the selected postId, revision, consent, and pricingVersion, and waits for the owner’s approval the same way. Automatic mode starts only eligible AI recommendations within the limits.
  5. Action pause on POST /boosts/settings stops new boosts and pauses owned campaigns. Unknown X requests retain reservations and are reconciled without creating duplicates.

Use request_access with consent:true to record a request for X approval, or withdraw_access to withdraw and pause promotion, both on POST /boosts/settings. MCP tools get_boosts, configure_boosts and spend_boosts expose the same controls; POST /boosts and control_boosts remain as deprecated names that take every action. An API key cannot bypass promotion approval, settled funds, or consent. See the boost screen and credit terms.

One twin, one mission

Your mission and approved information belong to your twin across every account you enable. Read GET /mission, then save PATCH /mission with goal, optional category, and the current revision (zero for the first save). Setup is free and needs no service connection. Changing the mission pauses accounts and returns queued drafts for review while keeping each service’s pace and limits. Already dispatched work may finish. New connections inherit the saved mission. A dating mission cannot use Gmail research or ongoing Gmail or iMessage autopilot, and X autopilot starts only when the goal or X facts mention “adult” or “18+”.

MCP exposes get_twin_mission and update_twin_mission. Uploaded information uses /persona/sources and is shared across writing services after you approve it. Choose accounts and tune service controls on the Autopilot page.

PATCH /api/v1/mission · free
{
  "goal": "Help me find an AI engineering role using my verified projects.",
  "category": "job",
  "revision": 0
}

Email twins: X, Gmail, or both

Start at Email Twin. Connect Gmail through Google, choose a sales or inbox mission, and review messages before selecting what to send. Google-only accounts can use email without X. An existing X user connects Gmail to the same account; a Google user can explicitly link X. Credits and drafts stay with that account.

GET /email?mission=UUID&page=0&filter=draft returns connection permissions, missions, 25 messages per page, state counts, folder totals in tabCounts, clearableCount, recent inquiries, and current writing prices. The three folders are draft (default, including writing or failed drafts), queued (including in-flight or unresolved sends), and sent (confirmed sends, newest first). Inspect connection.available, canRead, canSend, and aiAvailable. The human must complete Google consent; an API key cannot connect their mailbox.

Prepare a mission and drafts

POST /email/drafts accepts an action envelope for missions, imports and drafts, and never sends. POST /email/send takes the sending actions and POST /email/delete the deleting ones, with the same envelope; POST /email remains as a deprecated name that takes every action. save_mission takes data with id (UUID), name, kind (sales or inbox), goal, fromEmail, senderName, postalAddress, and dailyLimit (1–50). Include the current revision when updating. Saving pauses the queue. Import contacts with action: import, missionId, and data: up to 25 records containing id, email, sourceUrl, evidence, and reason. Optional name, company, description (up to 240 characters), country, subject, and body add context and a prepared draft. Retries preserve existing drafts.

For inquiries, sync refreshes up to 20 recent Gmail messages; reply takes missionId and inboxId to create a threaded draft. edit takes id and data with revision, subject, and body. Manual writing, imports, and Gmail operations are free. generate costs 0.20 prepaid credits per started attempt and takes id plus data with revision, consent:true, and maxChargeCents:20. Supply a stable Idempotency-Key. Retry the same key after a lost response; do not silently purchase another attempt.

Choose contacts and draft introductions

The Contacts checklist shows a brief description, source, and contact history. GET /email/contacts?mission=UUID&page=0&status=uncontacted&q=consulting returns 50 contacts per page. Status accepts all, uncontacted, or contacted. Search covers names, companies, emails, and descriptions.

contacted and lastContactedAt (Unix milliseconds) use confirmed Neurvona sends to the same address across your missions. External Gmail sends are not backfilled. deliveryState separately identifies queued, sending, or uncertain delivery. draft includes id, state, revision, and hasBody; canGenerate excludes protected or suppressed contacts. Mission-wide counts contains total, contacted, and uncontacted; total reflects search and status. Deleting drafts preserves this contact list.

Prepare a blank draft for an existing contact · free
{
  "action": "draft_contact",
  "id": "CONTACT_UUID"
}

This returns the existing draft unchanged or creates an empty one. Use its id and revision with edit for free, or generate after approving 0.20 credits per writing attempt. To generate a checklist selection, present the total price first and call generate sequentially with a distinct stable idempotency key per draft. The website supports up to 100 selected contacts: 20 credits for 100 existing contacts, without buying another research run. Keep the page open while writing; Stop finishes the current email and leaves completed drafts saved. Nothing sends automatically.

Choose how many emails to research

generate_batch takes missionId and data containing the current revision, audience (10–500 characters), optional count (1–100, default 20), consent:true, and maxChargeCents. Supply a stable Idempotency-Key. Each target costs 0.25 credits, with a 5-credit minimum: the default 20 cost 5 credits and 100 cost 25. Set maxChargeCents to the approved quote in hundredths of a credit. The quote is reserved before any provider call and starts background research targeting that many new business contacts and tailored drafts. Each draft connects a concrete fact from the recipient’s business to one relevant application of your offer, with a specific subject and question. Thin or unsupported matches are skipped. Only addresses published on the business’s own website are accepted. Existing contacts are skipped. The final count can be lower if verification falls short; started research uses the quoted credits. Nothing is sent. Through an API key, a run over 5 credits answers 403 approval_required until the owner approves it while signed in.

POST /api/v1/email/drafts · after approval of the 25-credit price
{
  "action": "generate_batch",
  "missionId": "MISSION_UUID",
  "data": {
    "revision": 0,
    "audience": "US founders, consultants, and small agencies",
    "count": 100,
    "consent": true,
    "maxChargeCents": 2500
  }
}

Poll GET /email?mission=UUID and inspect research.jobs for id, state, generated, target, and note. Terminal states are complete, partial, or canceled. One run per account can be active. stop_generation takes the job id; a run canceled before provider work starts is refunded. In-flight work may finish; ambiguous research calls are never repeated automatically.

Prepare a follow-up

Use a confirmed sales introduction to prepare one follow-up after 7, 14, or 30 days. Preparation is free and returns a blank draft; writing is optional at the usual 0.20-credit price. It needs explicit inbox access to verify the original conversation. The subject stays locked, and you review and approve the follow-up separately. Sending stops if the conversation has a newer message or the recipient opts out.

POST /api/v1/email/drafts · prepare only
{
  "action": "followup",
  "id": "ORIGINAL_DRAFT_UUID",
  "data": {
    "revision": 0,
    "afterDays": 7
  }
}

GET /email includes activity with sent, contacts, sentLast7Days, lastSentAt, repliesSeen, and optedOut. Sent means Gmail accepted the message. Replies count what an inbox refresh or follow-up check has seen, and stay counted after inbox copies expire: a sent message keeps the first reply’s time as replied_at, never its text. These counts do not track opens or actual delivery.

Send only approved messages

POST /api/v1/email/send · after the owner reviews these exact drafts
{
  "action": "queue",
  "missionId": "MISSION_UUID",
  "data": {
    "revision": 0,
    "consent": true,
    "selected": [
      {
        "id": "DRAFT_UUID",
        "revision": 1
      }
    ]
  }
}

The current mission revision and every selected draft revision are required. Up to 25 approvals per request. Only verified Gmail sender addresses work; sales emails also require a business mailing address and include an unsubscribe link. The default is 20 messages per day (the owner’s calendar day), at most 50 per account, sent only during the owner’s sending hours in their time zone (outreach and follow-ups Mon–Fri, 9 AM–5 PM; replies every day, 7 AM–10 PM; see sendingHours in GET /me) and at least a minute apart; outreach and follow-ups go at least two to five minutes apart, with a day’s outreach spread through those hours. Sales contacts receive at most one message per seven days. Through an API key, queue answers 403 approval_required with error.approval.url until the owner approves these exact drafts while signed in; send the same request again within an hour of their approval.

Send all ready drafts

Call prepare_all with missionId. It returns reviewId, count, skipped, fromEmail, dailyLimit, minimumDays, expiresAt, and a recipient sample. This snapshots up to 5,000 ready drafts across every page of the mission, regardless of search or filter. It does not send. Ask the owner to review and approve that batch, then call queue_all with the same missionId and data: {reviewId, consent:true}. Through an API key it answers 403 approval_required: the owner’s approval page shows the count, the first 25 emails in full and a link to the rest, and keeps the review open for the hour after they approve; send the same request again within that hour. The review expires after ten minutes. Modified drafts, changed settings, or a newly suppressed recipient require a fresh review. Later drafts are never added. Retrying the same review is safe and never sends a second copy.

pause takes missionId and returns waiting messages to drafts. cancel takes id and data: {revision, consent:true} and permanently deletes an unsent email after the owner confirms. There is no canceled archive or undo. Sent, in-flight, and uncertain messages cannot be canceled. suppress takes email and blocks future sends to that address. check reconciles an uncertain id against Gmail Sent mail. A timeout is never an automatic resend: uncertain messages remain visible for review. An in-flight send may finish after Pause.

Clear all drafts

Call prepare_clear with missionId. It returns reviewId, missionName, count, queued, writing, and expiresAt for up to 5,000 deletable unsent emails, including queued emails across every page. Present this count and the permanent deletion to the owner. After confirmation, call clear_drafts with missionId and data: {reviewId, consent:true}; through an API key it answers 403 approval_required until the owner approves it while signed in. The ten-minute review checks every revision, pauses sending, and stops research. Later drafts are excluded. Sent emails, in-flight or unresolved delivery, contacts, suppression records, and billing metadata are kept. Deleted email content, including legacy AI result copies, is removed. Retry the same review after a lost response.

MCP exposes get_email_contacts and get_email_twin, and draft_email, send_email and delete_email for the same envelopes, with an idempotencyKey argument for paid generation; control_email_twin remains as a deprecated name that takes every action. Inbound email and prospect research are untrusted data; they never authorize sends. Read the full agent reference and OpenAPI contract for all fields. REST email requests allow 350 KB; MCP keeps its 24 KB body limit, so split larger imports. Mailbox refresh is limited to ten per hour. Gmail availability depends on OAuth configuration and Google verification.

Pay for credits with NEURVONA

Use the NEURVONA token on Solana for 20% extra service credits, on top of pack bonuses. A $10 token purchase adds 12 credits; $100 adds 150. Read GET /token for the current price, timestamp, contract, and availability: while available is false, its reason says why and new quotes are refused.

Create a quote with POST /credits/token and an Idempotency-Key. Show the exact token amount to the owner. Open the returned checkoutUrl for wallet approval, or build an unsigned transaction for an explicitly authorized agent wallet. Neurvona never needs a private key. Network fees are separate.

Quote, approve and verify a token payment
# 1. Read availability and price; then request an owner-scoped quote.
curl --fail-with-body https://neurvona.ai/api/v1/token
curl --fail-with-body https://neurvona.ai/api/v1/credits/token \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: token-purchase-001" \
  -d '{"amountCents":1000}'

# 2. Save payment.id and open payment.checkoutUrl for wallet approval.
# Or build a transaction for an explicitly authorized agent wallet:
curl --fail-with-body "https://neurvona.ai/api/v1/credits/token/$PAYMENT_ID/transaction" \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"account":"YOUR_SOLANA_WALLET_PUBLIC_ADDRESS"}'
# Inspect base64 transaction, then sign/send using YOUR wallet.
# Never send Neurvona your private key. Do not sign an expired quote.

# 3. Confirm. Repeat at most every 15 seconds until payment.state is paid.
curl --fail-with-body "https://neurvona.ai/api/v1/credits/token/$PAYMENT_ID/verify" \
  -H "Authorization: Bearer $NEURVONA_API_KEY" \
  -H "Content-Type: application/json" -d '{}'
# An optional {"signature":"..."} avoids reference lookup.
# GET /me returns the updated shared service-credit balance.

The price is locked for five minutes. Credit only after payment.state is paid; pending is not proof of a failed payment. Verification checks finalized mainnet execution and the exact mint, amount, recipient, reference, net amount received, and deadline. Duplicate verification cannot add credits twice. A payment made before expiry can still be verified later. Reuse the same quote and request key after a timeout.

MCP exposes get_token_market, create_token_checkout, get_token_checkout, build_token_transaction, and verify_token_checkout. None signs or submits a payment. Call verification at most every 15 seconds. Limits: 20 quotes per account per hour, $100 per account and $500 total per rolling day, including open quotes. Low liquidity or unavailable prices pause new quotes. These credits share the normal balance. Paid advertising additionally requires settled USD backing; receiving tokens does not convert them to cash. Late, incorrect, and duplicate transfers require support review.

Retries without duplicate charges

For every intended generation, create one Idempotency-Key: 8–64 letters, digits, dashes, or underscores. MCP requires the same value in idempotencyKey. Save it with the input. Retry the exact same input and key after a lost response; a completed request returns its original result with replayed: true and no new charge.

  • A different input with the same key returns 409.
  • A request still running returns 409; retry the same key after a delay.
  • A confirmed failed request needs a new key; its error message says so.
  • Do not generate a new key just because the connection timed out.
  • Pause, resume, and settings changes are not covered by generation idempotency. Read status before retrying an ambiguous mutation.

REST POST /posts needs the header too. Until 2026-11-11 a request without one still runs, and its response carries Deprecation, Sunset and Link headers; from then it is refused with 400 idempotency_key_required before any charge.

Errors you can handle

REST error shape
{"error":{"code":"insufficient_credits","message":"Not enough credits. Add credits at https://neurvona.ai/twin/autopilot#credits.","requestId":"8f1c2d3e4a5b6c7d-SJC"}}
HTTPCodeWhat to do
400invalid_request / invalid_jsonCorrect the field named in the message, or send valid JSON.
401invalid_api_key / api_key_expiredCheck or replace the key; revoked and expired keys cannot be used.
402insufficient_credits / negative_balance / plan requiredAdd writing credits or restore your plan, as the message explains. negative_balance means a refund or dispute took back credits already used; new credits repay it first.
403insufficient_scope / approval_required / approval_deniedUse a key with error.scope; give error.approval.url to the owner and send the same request after they approve; a declined request should not be asked again.
409idempotency_conflict / generation_failed / setup requiredRead the message. A running request can be retried with the same key. generation_failed means the earlier attempt ended; another paid attempt needs a new key.
413payload_too_largeShorten the body to the limit in the message.
429rate_limited / concurrent_requestRespect Retry-After; use backoff. Only one generation per account at a time.
500server_errorBack off. Reuse the same idempotency key after an ambiguous generation failure.
502generation_failedThe message says what the attempt cost: nothing for a request the provider refused, the measured provider cost for unreadable output, the reservation when the outcome is unknown. Inspect usage before deciding to submit a new paid attempt.
503unavailable / platform_capacityNeurvona is temporarily at capacity and nothing was charged. Back off and retry later with the same key.

Error bodies include a requestId, the request’s Cloudflare Ray ID, also sent as the X-Request-Id header. Include it when you contact support.

In MCP, valid tool calls report execution failures in the tool result with isError: true, with the same code and requestId. A successful HTTP transport does not mean the tool succeeded.

Limits and support

600 requests per key per UTC hour, plus a separate 600 for pausing, stopping and canceling, so those always work. Once the first 600 are used, MCP initialize, ping, tools/list and notifications count in the second, so a client that reconnects can still pause. 120 generation requests per account per hour. One active generation per account. REST and MCP share these limits. JSON bodies are limited to 24,000 bytes, including overhead. Binary transcription uploads allow 25 MB. Source text may need to be shortened for multibyte characters.

Use HTTPS and server-side calls. No outbound developer webhooks, OAuth client registration, automatic wallet signing, or immediate publish endpoint are available. Poll status and activity at a reasonable interval. Credentials and enabled provider scopes are deployment-specific.

Need help? support@neurvona.ai.

Changelog

Version 4.2.0. Each change to a REST path, field, default, error or MCP tool adds a dated entry, newest first. The same list ends llms.txt.

  • 2026-10-12 · 4.2.0: Each email draft from GET /email (MCP get_email_twin) has review_reason: why ongoing autopilot left it for the owner (model_review, sensitive, content_rules, unsupported, license or unverified), or null. A draft waiting for review with no note of its own says why in error, for example "Your twin asked you to review this one before it goes."
  • 2026-10-11 · 4.1.2: GET /autopilot setupUrl is https://neurvona.ai/twin/autopilot#x-autopilot (it was https://neurvona.ai/twin, which now redirects to Autopilot), and the 409 autopilot_unavailable messages point there too. The 402 insufficient_credits message from POST /posts says to add credits at https://neurvona.ai/twin/autopilot#credits, and the 409 no_profile message says to add background at https://neurvona.ai/twin/autopilot#information. https://neurvona.ai/developers is now a public page for visitors who are not signed in; signed-in owners go from it to their API keys at https://neurvona.ai/twin/autopilot#tools.
  • 2026-10-11 · 4.1.1: queue_all returns the same lastSendBy as the prepare_all it confirms, and the owner's approval of an API key's queue_all names the same date: both count the emails the campaign already queued (queue_all counted only the batch) and what it sent that day, and the window open now holds only what its remaining minutes allow. A reply, follow-up or cold introduction that ongoing autopilot queued and that went back to review for its age has an error starting "Check before sending.", so prepare_all leaves it out and counts it in held, and it is approved on its own.
  • 2026-10-11 · 4.1.0: Email goes only during the owner's sending hours in their time zone: outreach and follow-ups Mon–Fri 9 AM–5 PM, replies to people who wrote first every day 7 AM–10 PM. An email queued outside them (queue, queue_all, ongoing autopilot) waits for the next opening. Outreach and follow-ups go at least 2 to 5 minutes apart, with a day's outreach spread through the hours; replies keep the one-minute spacing. A campaign's dailyLimit and ongoing autopilot's daily limit count the owner's calendar day; the 50-a-day account maximum stays a rolling 24 hours. Replies and follow-ups that ongoing autopilot queued and that have not gone within two days go back to review, and so do its cold introductions from research after 30 days. GET /me (MCP get_account) returns account.timezone (IANA), account.timezoneSource (browser, manual, x_autopilot, or fallback with America/Chicago until one is known) and sendingHours: for gmail_outreach, gmail_reply, linkedin, instagram and imessage, the weekdays, opening and closing times, a label and the window open now or next. queue and queue_all return sendingHours {timezone,hours}; prepare_all also returns lastSendBy and lastSendLabel, when the last email in the batch would go behind the campaign's queue at its pace in those hours (an estimate). The owner's approval of an API key's queue or queue_all names the hours and the estimate. followup sets followup_after to the first moment in the owner's outreach hours at least afterDays×24 hours, and 20 to 180 minutes, after the introduction (it was exactly afterDays×24 hours), so a follow-up never goes at night or on a weekend.
  • 2026-10-11 · 4.0.1: POST /persona/voice takes recordings of 10 to 45 seconds, at most 2,160,044 bytes (it was 60 seconds): a longer one answers 413 file_too_large or 400 invalid_audio before anything is reserved, and GET /persona/voice and GET /persona/capabilities give maxSeconds 45. The speech check counts other speech in any language: a word in another alphabet counts each of its letters, so the words read over someone else's speech in Russian, Chinese or any other script fail the check as English speech does. Through an API key, the approval of a video, live_video or x_live job shows the owner's X profile photo and covers that photo alone: if the X photo changes before the key sends the request again, it answers 403 approval_required for the new photo, and the video twin is made only from the photo the owner approved. A video twin whose creation stopped part way and is still unconfirmed ten minutes later is listed by GET /persona/avatars as uncertain, and DELETE /persona/avatars?id= removes it, deleting at Anam whatever was made under its name (it answered 409 avatar_pending). A video job that finds such a video twin, or an uncertain one, for the current X photo answers 409 avatar_preparing and says to remove it. A voice or video clip says "This is an AI-generated clip." only once its recording has started, so the downloaded file starts with it; a recording that has not started within 30 seconds fails like a twin that never got ready.
  • 2026-10-11 · 4.0.0: POST /persona/voice requires script, the token from GET /persona/voice?script=new (MCP get_persona_voice with script:true), whose setup.script.text the owner reads aloud in the recording: a consent sentence and eight random check words. After the price is reserved, xAI speech-to-text checks that the recording says those words and little else; a recording that does not, or a check that cannot finish, ends with voice.state failed and chargedCents:0 and never reaches Cartesia. Without script it answers 400 voice_script_required, with another account's token 400 voice_script_invalid, and with one older than three days 409 voice_script_expired. Saved voices record consent version personal-voice-v2. video, live_video and x_live jobs require photoAttestation:true as well as useXPhoto:true (400 avatar_consent_required): the owner's confirmation that their X profile photo shows them and that they are 18 or older, which their video twin records with its version and time. Through an API key, a video job whose video twin the owner has not attested to answers 403 approval_required until they approve it while signed in. GET /persona/avatars and DELETE /persona/avatars?id= (MCP get_persona_avatars and remove_persona_avatar) list the owner's video twins and remove one, at Anam too. Every voice and video clip starts with the spoken words "This is an AI-generated clip." before its script.
  • 2026-10-11 · 3.2.1: POST /persona/jobs with kind x_live answers 403 account_restricted for an account on hold, before anything is reserved or an approval is asked for. For a new account, prepare_all's dailyLimit and minimumDays and the dailyLimit that queue and queue_all return give the pace the send claim keeps, at most 10 outreach emails a day, instead of the campaign's own limit. Google Calendar: cancel_event is never counted toward or refused by the daily invitee limit, and a change that notifies nobody but the owner (a Docs change, an event without other invitees) never answers 409 invitee_limit.
  • 2026-10-11 · 3.2.0: An account Neurvona put on hold answers 403 account_restricted when it approves or queues email (queue, prepare_all and queue_all), starts X autopilot (POST /autopilot/resume) or boosts, or confirms a Google change; it still reads and drafts, and nothing it approved earlier is sent while the hold lasts. Every REST request and MCP message with a key of a suspended account answers 403 account_restricted. A new account (under 14 days old, without a card or plan payment) sends at most 10 outreach emails a rolling day and one email every 5 minutes; prepare_all puts at most 25 drafts in one batch and returns left and batchLimit for the rest, and queue_all refuses a larger one with 409 new_account_limit. GET /email returns accountStatus and accountLimits. Google Calendar changes notify at most 20 people a rolling day for a new account and 100 for any other, not counting the owner's own addresses (409 invitee_limit at prepare or confirm), never anyone on the owner's do-not-contact list (409 recipient_suppressed), and an account prepares at most 60 Google changes an hour (429 rate_limited).
  • 2026-10-11 · 3.1.0: Paid writing is charged for what the provider did: a request the provider refused (400, 401, 403, 404 or 429) or that never reached it costs nothing, output that could not be read or that the posting rules rejected costs the provider's measured cost (never more than the reservation), and only an attempt whose outcome is unknown, such as a timeout after sending, keeps its reservation. The 502 message says which applied. An email draft too large to send answers 400 context_too_large before anything is reserved. A paid request refused because the balance is below zero, after a refund or dispute took back credits already used, answers 402 negative_balance (it was insufficient_credits) with the amount in its message, and GET /me returns credits.outstandingCents and credits.outstandingCause. New credits repay the balance first. A plan refund now revokes only its share of the allowance, unused allowance first, and a dispute that Neurvona wins, or an inquiry that closes, returns the credits it held.
  • 2026-10-11 · 3.0.2: PATCH /autopilot keeps reposts as saved unless the request sends topics, and turning reposts on for a running autopilot answers approval_required like any other loosening. Approval pages show in full the text a request would use (a source's content, the autopilot purpose and facts, a job's script, a research audience), and for queue_all the count, the first 25 emails in full and a link to the rest. An approval for a paid start is used in the same step that reserves its credits, so a refused reservation keeps it for the retry; a spent one answers 409 approval_used. Pausing everything in the console ends every waiting or unused approval. MCP initialize, ping, tools/list and notifications count in the stop bucket once a key has used its 600 requests, so a client that reconnects can still pause. draft_email, prepare_google_workspace and configure_boosts declare destructiveHint:true, since they overwrite drafts, previews, imports and settings, and prepare_google_workspace's outputSchema allows operation:null, which cancel returns for an unknown id. An action a split tool does not take names the split tool of the same area. The drafts scope covers paid writing including email research (generate_batch); spend covers paid persona research, media, voice and token quotes.
  • 2026-10-11 · 3.0.1: email save_mission: a blank senderName on update now takes the name on the connected Google account, as documented; omitting senderName keeps the saved name. The email suppress action counts on Neurvona's shared opt-out list only once the owner has emailed that address, so it can never block someone for every sender by itself.
  • 2026-10-11 · 3.0.0: Keys have scopes: read plus any of drafts, send, autopilot and spend. An operation or action outside them answers 403 insufficient_scope with error.scope, and MCP tools/list shows only the tools a key can use. New keys default to read and drafts, expire after 90 days unless another expiry is chosen (an expired key answers 401 api_key_expired), and may charge at most 20 credits a rolling day unless another limit is chosen (409 key_spending_limit). Keys created before this version are legacy keys with every scope: they keep reading and drafting, and their sensitive actions wait for the owner as below. Replace them with scoped keys. GET /me returns key. consent:true is no longer the owner's authorization. Through any key, email queue and queue_all, clear_drafts, Google confirm, POST /autopilot/resume, a PATCH /autopilot that loosens a running autopilot or changes what it writes, boost enable and approve, saving an enabled persona source, voice setup, x_live, and paid jobs, transcriptions and research runs over 5 credits answer 403 approval_required with error.approval {id,url,state,expiresAt,title}. The owner approves at the url while signed in; the identical request then succeeds once within an hour, with revisions checked again as it runs. approval_denied means the owner declined. The email, Google and boost tools are split by risk: POST /email/drafts, /email/send and /email/delete (MCP draft_email, send_email, delete_email), POST /google/read, /google/prepare and /google/apply (read_google_workspace, prepare_google_workspace, apply_google_workspace), and POST /boosts/settings and /boosts/spend (configure_boosts, spend_boosts), with accurate MCP annotations and an outputSchema. POST /email, /google and /boosts and control_email_twin, control_google_workspace and control_boosts remain as deprecated names that take every action. Pausing, stopping and canceling (pause_autopilot, stop_persona_job, email pause, cancel and stop_generation, boost pause and withdraw_access, Google cancel) count in their own 600-request bucket per key, so they work after a key used its requests. REST POST /posts requires an Idempotency-Key: until 2026-11-11 a request without one still runs and its answer carries Deprecation and Sunset headers; from then it is refused with 400 idempotency_key_required.
  • 2026-10-10 · 2.5.0: Every email opt-out is shared across Neurvona as a keyed hash of the address. Outreach to an address that bounced as nonexistent for any sender, opted out from two senders, or asked Neurvona itself to stop is refused with 409 recipient_suppressed when generated or queued, before any charge, and leaves the queue as suppressed when sent; replies to people who wrote first are not affected. A cold introduction to an address two other senders emailed in the last 30 days, or to a domain that received 20 cold introductions in the last day, returns to drafts with the reason in error. Nothing is charged. A personal Gmail account (no Google Workspace domain) needs a one-time confirmation in the console before sales outreach: queue and queue_all answer 409 consumer_ack_required until then, and it sends at most 10 outreach emails a rolling day. Three addresses that bounced among the last 50 outreach emails, or five unsubscribes among the last 100, stop Gmail sending at the account gate with every approval kept. Addresses that cannot receive email as written are refused with 400 invalid_recipient. import accepts {contacts,listSource} as well as a list, and returns skipped {undeliverable,excluded,roleInbox,personal}: without listSource, role inboxes and personal mailboxes are skipped as research skips them. save_mission takes purpose (commercial, job_search or recruiting; job search and recruiting emails carry no mailing address or "Business introduction"), and a blank senderName is the Google account's name. generate_batch takes skipEurope. GET /email/contacts returns contactKind (person or organization), and research skips pages that ask for no solicitations near their address.
  • 2026-10-10 · 2.4.0: POST /posts charges nothing, and uses no free post, when none of the drafted posts passes the posting rules: it answers 502 generation_failed and says so. In a post only an offer counts as money (an amount, a discount, refund, coupon or deposit, or a guarantee the owner gives), so words such as price, fees or "I agree" no longer drop it; a range of years is not a phone number; and a short bracket such as [Day 3] or [FREE] is ordinary text, while [Name] or {first_name} still is not. email prepare_all leaves out drafts whose error starts "Check before sending." and returns their number as held (no longer in skipped): queue each one on its own after reading its note. Research and individual drafts read names from the body only, so a Title Case subject is never held, and weekdays, months, team words such as "Front Desk Team", "24/7" and "40 percent" written for a source's "40" no longer count as unsupported.
  • 2026-10-10 · 2.3.0: Every email, post and text the twin writes passes one content check before it can be queued; the writers of features behind flags are not covered yet. A generated email draft that ends with a sign-off and a name, uses Markdown, gives a link, contact details or a long number the owner or the inquiry did not supply, or mentions money or a commitment comes back with the reason in error ("Check before sending. ..."); editing or approving it clears the note. generate_batch never targets role inboxes such as support@, billing@, security@, admin@ or dpo@, and prefers a named person's address over info@ or contact@. A researched draft with a placeholder such as [Name] is not saved; one that breaks another content rule, states numbers, quotes or names its sources do not support, or nearly repeats another email in the run or one sent recently is saved at revision 1 with the reason in error, so ongoing autopilot never queues it. A company its page does not name is saved blank. POST /posts drops a post with a placeholder, or with contact details, a long number or money terms that the request, profile and approved sources did not supply. Writers keep to the owner's language and never mix languages.
  • 2026-10-10 · 2.2.0: Temporary Gmail failures (429, 5xx, timeouts) hold queued emails and retry with growing backoff and Retry-After instead of pausing the campaign. A revoked grant, a refused access, three emails in a row that Gmail refused or an uncertain send stops sending at the account gate and keeps every approval; GET /email connection.needsReconnect and GET /google needsReconnect are true until the owner reconnects, and Google tools then answer 409 google_revoked. Only a sender or campaign change returns queued emails to drafts. X autopilot skips a check and tries again after temporary X, token or plan-check failures, longer each time, and pauses after six in a row; a read or post X refuses fails without pausing, and the monthly limit, a low balance and a failed receipt email no longer pause. A decision that breaks a posting rule gets one corrective call and, still unusable, is skipped and not charged; three failed or unusable checks in a row pause. A LinkedIn or Instagram rate limit returns the post to the approved queue with a growing wait; lost access pauses that channel, and its posts need approval again after the reconnect. A temporary Instagram error on the publishing step leaves the post uncertain.
  • 2026-10-10 · 2.1.0: One version for OpenAPI and MCP, and this changelog. The generate_batch count default is documented as 20, which the server has used since October 8. Token checkout text follows the deployment; GET /token reports whether new quotes are available. The docs list every endpoint and MCP tool, including /persona/voice, GET /credits/token/{id} and HEAD /persona/jobs/{id}/file. Errors carry requestId, the Cloudflare Ray ID, in the body and the X-Request-Id header. Malformed JSON is 400 invalid_json and an oversized body 413 payload_too_large. Autopilot and boost refusals have their own codes, such as verify_email, insufficient_credits and revision_conflict.
  • 2026-10-09 · 2.0.0: A full shared capacity pool returns 503 platform_capacity, and nothing is charged. The dating category returns 409 dating_x_only for Gmail research and ongoing Gmail or iMessage autopilot. X autopilot needs "adult" or "18+" in the goal or X facts. A session or recording the twin never joins ends with chargedCents:0. Inbox copies are deleted 30 days after arrival, or at once when inbox access is removed, replies are switched off or paused, or the twin is paused. A reply whose copy is gone fails with inquiry_unavailable. GET /email activity.repliesSeen keeps counting after inbox copies expire. followup returns 409 queue_full at 5,000 unsent drafts.
  • 2026-10-08 · 2.0.0: GET and POST /google, with MCP get_google_workspace and control_google_workspace: Calendar and Docs reads and owner-approved changes. Plus, Pro and Max plans with monthly included credits. The generate_batch count defaults to 20 contacts (5 credits) instead of 100.
  • 2026-10-07 · 2.0.0: generate_batch accepts count 1–100 at 0.25 credits per target, with a 5-credit minimum. Eligible accounts get 10 starter credits once.
  • 2026-10-05 · 2.0.0: GET and PATCH /mission, with MCP get_twin_mission and update_twin_mission: one shared mission. Once it is saved, legacy autopilot mission and brief fields return 409. POST /posts accepts an optional topic. New token quotes are available again.
  • 2026-10-04 · 2.0.0: POST /email followup and GET /email activity. Raw transcription clients send mono 16 kHz 16-bit PCM WAV (inputFormat pcm16-wav).
  • 2026-10-01 · 2.0.0: Email twins: GET and POST /email and GET /email/contacts, with MCP get_email_twin, get_email_contacts and control_email_twin. cancel requires data {revision,consent:true}; id-only calls are rejected. New token quotes are paused.
  • 2026-09-30 · 2.0.0: NEURVONA token payments: GET /token and /credits/token. Boosts use shared credits. preview, enable and approve require pricingVersion shared-credits-v1, and older price acknowledgements are rejected. Recordings download from GET and HEAD /persona/jobs/{id}/file.
  • 2026-09-29 · 2.0.0: Persona sources, connections, capabilities, jobs, photo, voice and transcription.
  • 2026-09-29 · 1.0.0: REST at /api/v1 and MCP at /api/mcp.