# POST /completions Source: https://docs.curvelabs.org/api-reference/completions Use ThinkFeel through an OpenAI-compatible text completions endpoint. ThinkFeel supports an OpenAI-compatible text completions endpoint at `/api/v1/completions`. OpenAI SDKs for Completions, including AI SDK, can point their base URL to `https://playground.curvelabs.org/api/v1`. ```text theme={null} POST https://playground.curvelabs.org/api/v1/completions ``` This is different from the ThinkFeel SDK and CLI base URL setting, which should use only the site origin. Send either `prompt` or `messages`, not both. `model` must be your persona ID. ## Headers | Header | Type | Required | Description | | --------------- | ------ | ----------- | ------------------------------------------------------------------------------ | | `Content-Type` | string | Yes | Must be `application/json` | | `Authorization` | string | Conditional | OpenAI-style bearer API key for API-key billing | | `x-api-key` | string | Conditional | Alternative to `Authorization`; one key header is required for API-key billing | ## Body parameters | Parameter | Type | Required | Description | | ---------- | ---------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | | `model` | string | Yes | Persona ID UUID only | | `messages` | array | Conditional | Multi-turn text messages; accepts `user`, `assistant`, `system`, and `developer` roles with string or text-part array content | | `prompt` | string or string array | Conditional | Non-empty text prompt, as a string or one-item string array, when `messages` is omitted | | `n` | number | No | Number of completions, 1-5. Defaults to 1 | | `echo` | boolean | No | Prepend the prompt to the output text | | `stop` | string or string array | No | Stop sequence or sequences | ## Compatibility notes * Provide either `prompt` or `messages`. * When using `messages`, include the full conversation history, put `system` and `developer` context before the final user turn, and send non-empty content in that final user message. * `messages` supports `user`, `assistant`, `system`, and `developer` roles. * `model` must be your persona ID UUID provided during onboarding. * `prompt` must be a non-empty string or a single-element string array. * `n` is capped at 5. * Message content must be a plain string or an array of text parts. * Optional `timestamp`, `createdAt`, and `created_at` values are accepted and normalized when present. * Streaming is not supported on this V1 endpoint. `stream: true` returns an error. * `max_tokens` and `logprobs` are rejected. * Other OpenAI parameters are accepted but ignored: `temperature`, `top_p`, `presence_penalty`, `frequency_penalty`, `best_of`, `seed`, `suffix`, and `user`. * Output text is normalized, stop sequences are applied, and `echo` prepends the prompt. * Responses omit `usage`. ## Request ```bash theme={null} curl -X POST https://playground.curvelabs.org/api/v1/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY_HERE" \ -d '{ "model": "YOUR_PERSONA_ID", "prompt": "hey, how's your day?", "n": 1, "echo": false, "stop": ["\n\n"] }' ``` ## Response ```json theme={null} { "id": "cmpl-...", "object": "text_completion", "created": 1737656583, "model": "YOUR_PERSONA_ID", "choices": [ { "text": "pretty chill so far, you?", "index": 0, "logprobs": null, "finish_reason": "stop", "chunks": ["pretty chill so far, you?"] } ] } ``` # POST /generate Source: https://docs.curvelabs.org/api-reference/generate Generate an AI response based on conversation history. Use `/generate` for direct ThinkFeel requests. Send a persona ID and full message history. The response returns the selected final reply and optional alternatives. ```text theme={null} POST https://playground.curvelabs.org/api/v1/generate ``` ## Headers | Header | Type | Required | Description | | --------------- | ------ | ----------- | ----------------------------------------------------- | | `Content-Type` | string | Yes | Must be `application/json` | | `x-api-key` | string | Conditional | API key for API-key billing | | `Authorization` | string | Conditional | Alternative bearer format: `Bearer YOUR_API_KEY_HERE` | ## Body parameters | Parameter | Type | Required | Description | | ---------------------- | -------------------- | -------- | -------------------------------------------------------------------------------- | | `personaId` | string | Yes | Persona UUID provided during onboarding | | `messages` | array | Yes | Conversation messages to use as context | | `messages[].role` | string | Yes | `user`, `assistant`, `system`, or `developer` | | `messages[].content` | string or text array | Yes | Plain text, or an array of text parts shaped as `{ type: "text", text: string }` | | `messages[].timestamp` | number or string | No | Optional timestamp; `createdAt` and `created_at` are also accepted | | `includeVariations` | boolean | No | Return alternative reply choices. Defaults to `false` | `messages[]` must contain at least one message. Use `user` for the final user turn; `assistant` cannot be the last message. `system` and `developer` messages are accepted as text-only context and should be placed before the final user turn. The final user message must have non-empty content. Only text content is supported. ## Request ```bash theme={null} curl -X POST https://playground.curvelabs.org/api/v1/generate \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY_HERE" \ -d '{ "personaId": "YOUR_PERSONA_ID", "messages": [ { "role": "user", "content": "Hello!" } ] }' ``` ## Default response When `includeVariations` is `false`, the API returns the final reply and chunks. ```json theme={null} { "status": "success", "result": { "finalReply": "hey! what's up?", "chunks": ["hey! what's up?"] } } ``` ## Response with variations When `includeVariations` is `true`, the API may include `replyChoices`. ```json theme={null} { "status": "success", "result": { "finalReply": "hey! what's up?", "chunks": ["hey! what's up?"], "replyChoices": ["hey! what's up?", "hi there! how's it going?", "hey! good to hear from you"] } } ``` API-key `/generate` responses may also include a top-level `rateLimits` array when rate-limit metadata is available for your account. ## SDK and CLI notes The ThinkFeel SDK wraps `/api/v1/generate` and `/api/v1/personify`. It does not wrap `/api/v1/completions`, which remains the OpenAI-compatible endpoint. The ThinkFeel SDK package is currently `0.1.6` and supports: * `new ThinkFeel({ apiKey, personaId, baseUrl? })` * `generate({ messages, includeVariations? })` * `personify({ raw })` When setting SDK `baseUrl`, pass only the site origin, such as `https://playground.curvelabs.org`; the SDK appends `/api/v1` internally. # POST /personify Source: https://docs.curvelabs.org/api-reference/personify Rewrite source text into a persona voice enabled for your account. Use `/personify` when you already have source text and want to rewrite it in a persona voice enabled for your account. ```text theme={null} POST https://playground.curvelabs.org/api/v1/personify ``` ## Headers | Header | Type | Required | Description | | --------------- | ------ | ----------- | ---------------------------------- | | `Content-Type` | string | Yes | Must be `application/json` | | `Authorization` | string | Conditional | Bearer API key for API-key billing | | `x-api-key` | string | Conditional | Alternative to `Authorization` | ## Body parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------------------------------------- | | `personaId` | string | Yes | Persona UUID with `/personify` access | | `raw` | string | Yes | Non-empty source text to rewrite; not treated as instructions | ## Request ```bash theme={null} curl -X POST https://playground.curvelabs.org/api/v1/personify \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY_HERE" \ -d '{ "personaId": "YOUR_PERSONIFY_PERSONA_ID", "raw": "Thanks for reaching out. We can help answer customer questions faster while keeping the tone warm and clear." }' ``` ## Response ```json theme={null} { "personified": "thanks for reaching out. we can help answer customer questions faster while keeping the tone warm and clear.", "chunks": [ "thanks for reaching out.", "we can help answer customer questions faster while keeping the tone warm and clear." ] } ``` # Authentication Source: https://docs.curvelabs.org/authentication Authenticate ThinkFeel SDK, CLI, and OpenAI-compatible requests. Send one API key header with each request. ThinkFeel accepts either the `x-api-key` header or an OpenAI-style bearer token. Generate keys yourself after onboarding is approved. API-key billing is the standard path, so send one key header on every request. Payment challenges only appear on allowlisted self-serve endpoints or personas when Curve Labs enables that option for your account. ## Supported API key headers ```text theme={null} x-api-key: YOUR_API_KEY_HERE Authorization: Bearer YOUR_API_KEY_HERE ``` For OpenAI-compatible clients, send your key as `Authorization: Bearer`. The `x-api-key` header is still supported for direct ThinkFeel requests. ## Environment variables SDK and CLI projects should use: | Variable | Required | Notes | | ---------------------- | -------- | ---------------------------------------------------------------------------- | | `THINKFEEL_API_KEY` | Yes | API key created in Playground, through CLI login, or by the ThinkFeel Plugin | | `THINKFEEL_PERSONA_ID` | Yes | Persona UUID provided during onboarding | | `THINKFEEL_BASE_URL` | No | Origin only, such as `https://playground.curvelabs.org` | OpenAI-compatible clients should point their client base URL to `https://playground.curvelabs.org/api/v1`. Depending on the client library, you may need to store the same key as `OPENAI_API_KEY`. ## CLI login and profiles ```bash theme={null} npx thinkfeel login npx thinkfeel login --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel login --name "Local dev key" --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel login --profile work --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel profiles npx thinkfeel use work ``` `thinkfeel login` is the preferred way to set up keys for approved Playground users. It opens browser sign-in, creates a Playground API key after confirmation, encrypts the key to a local callback, and saves it in the ThinkFeel CLI profile without printing the unencrypted key. ## Agent-assisted setup Codex and Claude Code users can install the ThinkFeel Plugin from [CLI + Agents](/cli-agents). The plugin does not run `npx thinkfeel login`; it uses its own local helper with the same Playground browser approval flow, confirms the local env-file destination, then writes `THINKFEEL_API_KEY` and optional `THINKFEEL_PERSONA_ID` without exposing plaintext in chat. ## Non-interactive configuration ```bash theme={null} printf '%s\n' "$THINKFEEL_API_KEY" | npx thinkfeel configure --api-key-stdin --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --api-key-env THINKFEEL_API_KEY --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --profile work --api-key-env WORK_THINKFEEL_API_KEY --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --show ``` Use `--api-key-env` or `--api-key-stdin` for automation. Passing API keys as command arguments is intentionally unsupported because shell history and process lists can expose them. Never expose your API key in client-side or public code. Store API keys as environment variables or managed secrets, rotate keys periodically, and use HTTPS for all requests. # CLI and agents Source: https://docs.curvelabs.org/cli-agents Use the ThinkFeel package for local development, coding agents, and safe key setup. The npm package includes the TypeScript SDK, the `thinkfeel` CLI, and a `SKILL.md` file that tells coding agents how to use ThinkFeel safely. The ThinkFeel Plugin adds a separate Codex and Claude Code setup flow for agent-managed local env files. The plugin does not call `npx thinkfeel login`. It uses a local plugin helper, asks you to approve an env-file destination, opens the same Playground browser approval flow, and writes `THINKFEEL_API_KEY` to that env file. Use `thinkfeel login` when you want a standalone CLI profile. ## Install for agents Codex users should add the ThinkFeel marketplace and install the plugin: ```bash theme={null} codex plugin marketplace add artificial-affect/thinkfeel-plugin codex plugin add thinkfeel-plugin@thinkfeel ``` Start a new Codex thread after installation so Codex loads the ThinkFeel plugin skill and MCP server. Claude Code users can install the same plugin from the ThinkFeel marketplace: ```bash theme={null} /plugin marketplace add artificial-affect/thinkfeel-plugin /plugin install thinkfeel-plugin@thinkfeel ``` Run `/reload-plugins` or start a new Claude Code session after installation. ## Install the package or run one-off ```bash theme={null} npm i @curvelabs.org/thinkfeel # One-off usage without adding the package to a project npx --package @curvelabs.org/thinkfeel thinkfeel --help ``` ## Login, name keys, and switch profiles ```bash theme={null} npx thinkfeel login npx thinkfeel login --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel login --name "Local dev key" --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel login --profile work --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel profiles npx thinkfeel use work ``` ## Configure CI or local scripts ```bash theme={null} printf '%s\n' "$THINKFEEL_API_KEY" | npx thinkfeel configure --api-key-stdin --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --api-key-env THINKFEEL_API_KEY --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --profile work --api-key-env WORK_THINKFEEL_API_KEY --persona-id YOUR_THINKFEEL_PERSONA_ID npx thinkfeel configure --show ``` ## Generate, personify, inspect JSON, and clear config ```bash theme={null} npx thinkfeel generate "Can we talk later?" npx thinkfeel generate "Can we talk later?" --variations npx thinkfeel generate "Can we talk later?" --json npx thinkfeel personify "Thanks for reaching out. Send me the details when you have them." npx thinkfeel configure --clear --profile work ``` ## Inspect the package skill ```bash theme={null} cat node_modules/@curvelabs.org/thinkfeel/SKILL.md ``` ```markdown theme={null} --- name: thinkfeel-sdk description: Use when a coding agent needs to install, configure, or call the ThinkFeel SDK or CLI for generate/personify work. --- # ThinkFeel SDK Use this skill when a project needs ThinkFeel API access through @curvelabs.org/thinkfeel or the thinkfeel CLI. Rules: - Never ask the user to paste an API key into chat. - If the ThinkFeel Plugin is installed in Codex or Claude Code, prefer its Playground API-key credential gate for project env-file setup. - Prefer npx thinkfeel login for standalone CLI profiles. - Use the persona ID the user already has; do not invent one. - Verify setup with npx thinkfeel configure --show without exposing secrets. ``` ## Browser login URL details ```text theme={null} GET /api/thinkfeel/cli/login?state=...&name=...&source=cli&redirect_uri=http://127.0.0.1:PORT/thinkfeel/callback&recipient_public_key_jwk=... Required query params: - state: random value generated by the caller to protect the login session - redirect_uri: http loopback URL only (127.0.0.1, localhost, or ::1) - recipient_public_key_jwk: base64url-encoded RSA public JWK Optional query params: - name: display name for the generated API key - source: cli, codex, or claude_code Do not use this route as a general key-creation API. The browser-authenticated confirmation page returns only an encrypted `encrypted_api_key` value to the local callback. ``` Automated setup should use the ThinkFeel Plugin in Codex or Claude Code, or `npx thinkfeel login` for CLI profiles. Do not ask users to paste API keys into chat. If browser login is unavailable, use `configure --api-key-env` or `configure --api-key-stdin`. # Custom personas Source: https://docs.curvelabs.org/concepts/personas Design custom ThinkFeel personas for your product and audience. Instead of asking you to tune a generic model yourself, Curve Labs works with you to create a persona for your product. During onboarding, the team helps define the personality, audience fit, and boundaries. ## Personality traits * **Extraversion vs. introversion:** energetic and outgoing vs. thoughtful and reserved * **Emotional tone:** warm, professional, playful, or another use-case-specific tone * **Confidence level:** bold and assertive vs. humble * **Humor style:** dry wit, playful banter, or no humor ## Communication style * **Formality:** casual slang vs. professional language * **Verbosity:** concise replies vs. detailed explanations * **Emotional expression:** expressive vs. reserved * **Question frequency:** inquisitive vs. statement-focused ## Behavioral guidelines * **Role definition:** friend, peer supporter, coach, assistant, or another clear role * **Boundaries:** topics to avoid or handle sensitively * **Engagement style:** proactive vs. reactive * **Cultural context:** regional slang and cultural references ## Match personas to use cases * **Customer support:** patient and solution-focused * **Mental wellness:** non-judgmental and validating * **Entertainment:** engaging, playful, and creative * **Education:** encouraging and adaptive During onboarding, you receive a unique `personaId` in UUID format. Use that ID in all API requests. It is tied to your custom persona configuration and can be refined over time based on feedback and usage. # Cookbook API request examples Source: https://docs.curvelabs.org/cookbooks/api-request-examples Request and response examples for the cookbook quickstart, chat, and personify routes. ## `POST /api/quickstart` ### Request ```json theme={null} { "prompt": "hello", "personaId": "optional-uuid" } ``` ### Response ```json theme={null} { "text": "...", "model": "persona-uuid" } ``` ## `POST /api/chat` ### Request ```json theme={null} { "messages": [{ "role": "user", "content": "hello" }], "personaId": "optional-uuid" } ``` ### Response ```json theme={null} { "reply": "...", "model": "persona-uuid" } ``` ## `POST /api/personify` ### Request ```json theme={null} { "raw": "Base response to rewrite", "personaId": "optional-uuid" } ``` ### Response ```json theme={null} { "personified": "...", "chunks": ["..."], "model": "persona-uuid" } ``` ## Shared error response ```json theme={null} { "error": { "type": "validation | config | provider", "message": "..." } } ``` # Cookbooks Source: https://docs.curvelabs.org/cookbooks/index Practical build guides for ThinkFeel integrations. This section summarizes the current `curve-labs-cookbooks` examples. Use these guides for quick starts, then review the production checklist before launching. ## Repository snapshot | Field | Value | | ------------- | ----------------------------- | | Organization | `artificial-affect` | | Repository | `curve-labs-cookbooks` | | Latest commit | `f141cac` | | Commit date | July 6, 2026 | | Summary | signpost thinkfeel agent docs | ```bash theme={null} git clone https://github.com/artificial-affect/curve-labs-cookbooks.git cd curve-labs-cookbooks git log -1 --oneline ``` ## Available cookbooks Plain Node.js scripts for checking SDK configuration with environment variables. Accessible quickstart, multi-turn chat, and personify routes using ThinkFeel's non-stream responses. ## Reference pages Request and response examples for the cookbook quickstart, chat, and personify routes. Required controls before launching a cookbook example. Scripts and Chat SDK adaptation notes. # Local SDK check Source: https://docs.curvelabs.org/cookbooks/local-sdk-check Verify ThinkFeel SDK setup from a minimal Node.js project. Use this recipe when you want to verify local SDK setup without a UI. ## Environment variables ```bash theme={null} export THINKFEEL_API_KEY=your_thinkfeel_api_key export THINKFEEL_PERSONA_ID=your_persona_uuid # Optional export CURVE_PROMPT="hey what's up?" export THINKFEEL_BASE_URL="https://playground.curvelabs.org/api/v1" ``` ## Install and run ```bash theme={null} npm install npm start # Offline tests npm test ``` This local SDK check is for configuration testing only. It is not a deployed service and does not include user authentication, tenancy isolation, or abuse controls by default. ## Base URL behavior The cookbook examples use an OpenAI-compatible provider base URL, so `THINKFEEL_BASE_URL` defaults to `https://playground.curvelabs.org/api/v1`. ThinkFeel SDK and CLI setup are different. Pass only the site origin, such as `https://playground.curvelabs.org`, when configuring `ThinkFeel` directly. ## Auth setup New cookbook setup should use `THINKFEEL_API_KEY` and `THINKFEEL_PERSONA_ID`. The repo still reads legacy `CURVE_API_KEY` and `CURVE_PERSONA_ID` only when the matching `THINKFEEL_*` value is absent. Prefer `npx thinkfeel login` or `npx thinkfeel configure --api-key-env THINKFEEL_API_KEY` to avoid pasting keys into commands. # Next.js app cookbook Source: https://docs.curvelabs.org/cookbooks/nextjs-chat Run a full-stack ThinkFeel quickstart, multi-turn chat, and personify example. This cookbook includes quickstart, multi-turn chat, and personify pages. Quickstart and chat use the OpenAI-compatible provider base URL; personify calls the native JSON endpoint. ## Local setup ```bash theme={null} cd nextjs-example cp env.example .env.local npm install npm run dev ``` ## `.env.local` ```bash theme={null} THINKFEEL_API_KEY=your_thinkfeel_api_key THINKFEEL_PERSONA_ID=your_persona_uuid # Optional THINKFEEL_BASE_URL=https://playground.curvelabs.org/api/v1 ``` ## Included routes | Route | Purpose | | ---------------------- | ------------------------ | | `GET /` | Quickstart UI | | `GET /chat` | Multi-turn chat UI | | `GET /personify` | Native personify UI | | `POST /api/quickstart` | Completion sample | | `POST /api/chat` | Non-stream chat exchange | | `POST /api/personify` | Native personify rewrite | ## Key notes * Uses Vercel AI SDK provider setup with ThinkFeel's OpenAI-compatible base URL. * ThinkFeel completions are non-stream. The UI expects complete reply responses. * ThinkFeel personify uses the native `/api/v1/personify` JSON endpoint. * Tool-calling and some OpenAI parameters remain unsupported. * Error responses are grouped as validation, config, or provider errors. * If overriding `THINKFEEL_BASE_URL` for this OpenAI-compatible cookbook, include `/api/v1`. * For ThinkFeel SDK or CLI setup, use the origin only. * Legacy `CURVE_*` environment names remain fallback-only. * New setup should use `THINKFEEL_*` names. # Production checklist Source: https://docs.curvelabs.org/cookbooks/production-checklist Controls required before launching cookbook examples. Both cookbook READMEs state that these examples are starting points, not production-ready defaults. Do not expose cookbook routes publicly until you have added product-specific auth, abuse controls, monitoring, and data-handling policies. ## Required before launch * Authenticate and authorize every API route with user and tenant checks. * Apply edge and app rate limiting, throttling, and abuse controls. * Review CORS and CSRF policies. * Enforce strict request limits. * Set up structured logs, error reporting, and alerting for provider failures. * Store and rotate API keys in managed secret stores. * Enforce retention, deletion, and sensitive-data sanitization policies. * Define reliability and cost safeguards, including budgets, retries, and circuit breakers. # Testing and migration Source: https://docs.curvelabs.org/cookbooks/testing-migration Run cookbook checks and adapt chat SDK apps for ThinkFeel. Use the shipped scripts first, then move to live tests only after environment configuration is confirmed. ## Next.js cookbook scripts ```bash theme={null} cd nextjs-example npm run dev npm run test npm run typecheck npm run build # Optional live smoke test npm run test:live ``` ## Chat SDK changes * Replace streaming responses with non-stream completion calls for ThinkFeel. * Use persona UUID as the completion model identifier. * Send full multi-turn message history on each request. * Do not assume token streaming in client transport or UI state. # FAQ Source: https://docs.curvelabs.org/faq Answers to common ThinkFeel API questions. Beta access uses pricing close to the cost of the underlying models. This keeps beta usage fair. Curve Labs may introduce a free tier in the future based on community feedback. During your onboarding call, Curve Labs works with you to design a custom persona tailored to your use case. The team collaboratively defines personality traits, communication style, and behavioral guidelines that match your product needs. No. The API is stateless for conversation continuity. Send the relevant message history with each request and manage long-term conversation state on your end. For most production use cases, the default response is sufficient. Enable `includeVariations: true` when you want to show users alternative response options or inspect other replies the AI generated. Yes. Curve Labs encourages ongoing refinement. Contact support to adjust your persona based on real-world usage and feedback. You do not choose a model directly. Use your assigned persona ID as `personaId`, or as `model` on the OpenAI-compatible endpoint. Curve Labs keeps the request format stable as backend models evolve. Yes. Contact Curve Labs through [support](https://curvelabs.org/support) with your use case and expected volume. Higher limits are available for production-level projects. # Impact studies Source: https://docs.curvelabs.org/impact-studies/index Customer examples built with ThinkFeel. Use these studies to see which ThinkFeel endpoint fits each customer workflow. See how Unreel.ai uses `/completions` through OpenAI-compatible SDKs. See how Unbrowse.ai uses `/personify` with the Aiko agent. # Agent workflows: Unbrowse.ai Source: https://docs.curvelabs.org/impact-studies/unbrowse How Unbrowse.ai uses ThinkFeel to rewrite agent output in a persona voice. Unbrowse.ai agent workflow [Unbrowse.ai](https://unbrowse.ai/) turns website actions into tools that agents can call. It uses [`/personify`](/api-reference/personify) with the Aiko agent. The product can send the agent's draft output to ThinkFeel, then return the rewritten result in Aiko's persona voice before the user sees it. Use `/personify` when you already have source text and need to convert it into a specific persona voice. # AI video content: Unreel.ai Source: https://docs.curvelabs.org/impact-studies/unreel How Unreel.ai uses ThinkFeel for AI video content workflows. Unreel.ai AI video content workflow [Unreel.ai](https://unreel.ai/) helps creators produce AI video content for brand campaigns. It uses [`/completions`](/api-reference/completions) through OpenAI-compatible SDKs. Existing generation code can point at ThinkFeel by setting the SDK base URL to `https://playground.curvelabs.org/api/v1` and using a ThinkFeel persona ID as the `model`. Use `/completions` when your app already expects an OpenAI-style text completion response. # ThinkFeel Emotion AI API Source: https://docs.curvelabs.org/index Build emotionally intelligent AI replies with ThinkFeel, the Curve Labs API for custom personas, chat workflows, and OpenAI-compatible apps. ThinkFeel by Curve Labs Use ThinkFeel to generate replies for a custom persona. Send the messages you want the persona to consider, and receive a response your product can show or adapt. AI that understands context, tone, and emotional subtext. Work with Curve Labs to craft a persona tailored to your use case. Keep full control over conversation history and context. Pay pricing close to model costs during the early access beta. ## Install the tools ```bash theme={null} codex plugin marketplace add artificial-affect/thinkfeel-plugin codex plugin add thinkfeel-plugin@thinkfeel ``` Codex users should add the ThinkFeel marketplace and install the plugin. Start a new Codex thread after installation so Codex loads the ThinkFeel plugin skill and MCP server. ```bash theme={null} /plugin marketplace add artificial-affect/thinkfeel-plugin /plugin install thinkfeel-plugin@thinkfeel ``` Claude Code users can install the same plugin from the ThinkFeel marketplace. Run `/reload-plugins` or start a new Claude Code session after installation. ```bash theme={null} npm i @curvelabs.org/thinkfeel ``` The ThinkFeel SDK and CLI use the site origin for `THINKFEEL_BASE_URL`, such as `https://playground.curvelabs.org`. OpenAI-compatible clients use `https://playground.curvelabs.org/api/v1`. ## Where to start Request access, set up keys, and send your first ThinkFeel request. Learn supported API key headers, environment variables, and security rules. Review request and response details for each endpoint. Start from working example projects. ## Version ThinkFeel API documentation version: `0.1.3 Beta` Last updated: July 7, 2026 # Best practices Source: https://docs.curvelabs.org/operations/best-practices Keep ThinkFeel integrations clear, efficient, and secure. ## Maintain conversation context To keep multi-turn conversations consistent, always include previous messages. ```javascript theme={null} const conversation = []; // First exchange conversation.push({ role: 'user', content: 'What do you do for fun?' }); let response = await thinkFeel.generate({ messages: conversation }); conversation.push({ role: 'assistant', content: response.finalReply }); // Second exchange - includes full history conversation.push({ role: 'user', content: 'That sounds cool!' }); response = await thinkFeel.generate({ messages: conversation }); ``` ## Trim long conversations For very long conversations, consider truncating older messages to reduce latency. ```javascript theme={null} function trimConversation(messages, maxMessages = 20) { if (messages.length <= maxMessages) return messages; return messages.slice(-maxMessages); } ``` ## Never expose API keys Do not put API keys in client-side or public code. Do not hardcode keys: ```javascript theme={null} const response = await fetch(url, { headers: { 'x-api-key': 'abc123...', }, }); ``` Use managed environment variables or secrets: ```javascript theme={null} const response = await fetch(url, { headers: { 'x-api-key': process.env.THINKFEEL_API_KEY, }, }); ``` # Error handling Source: https://docs.curvelabs.org/operations/errors Handle ThinkFeel status codes and errors. The API uses standard HTTP status codes and returns detailed error messages. ## Status codes | Status | Meaning | Description | | ------ | --------------------- | ------------------------------------------------------------------------- | | `200` | Success | Request completed successfully | | `400` | Bad Request | Malformed JSON or invalid body on `/completions` and `/personify` | | `401` | Unauthorized | Invalid or missing API key | | `402` | Payment Required | Payment challenge for enabled self-serve personas when no API key is sent | | `403` | Forbidden | API key is not associated with an active billing account | | `404` | Not Found | Invalid persona ID | | `422` | Unprocessable Entity | Invalid request body or parameters | | `429` | Too Many Requests | Insufficient balance or quota exhausted on API-key billing | | `500` | Internal Server Error | Server error. Contact support if persistent | ## ThinkFeel endpoint validation errors The `/generate` and `/personify` endpoints return plain text for most validation and authentication errors. ```text theme={null} Unknown `personaId` was provided in the body. ``` Quota and unexpected server errors may return JSON, so clients should check the response content type before parsing errors. Requests without API-key headers may also receive a payment challenge instead of a JSON or plain-text error when self-serve payment access is enabled for the target persona. If a persona is not enabled for self-serve payment access, send an API key header. Unauthenticated requests can return `404` instead of confirming persona availability. ## OpenAI-compatible error format ```json theme={null} { "error": { "message": "Missing required `model`.", "type": "invalid_request_error", "param": "model", "code": null } } ``` # Rate limits Source: https://docs.curvelabs.org/operations/rate-limits Understand early access beta request limits. During the early access beta, API keys created in Playground use these default rate limits: | Window | Limit | | ---------- | -----------: | | Per minute | 25 requests | | Per hour | 100 requests | | Per day | 500 requests | These limits are subject to review and may be increased based on your use case. Contact Curve Labs if you need higher limits. # Quickstart Source: https://docs.curvelabs.org/quickstart Get approved, configure ThinkFeel, and send your first request. ThinkFeel is available through the Curve Labs early access beta program. Fill out the [request access form](https://curvelabs.org/request-api-access) with: * Your name and email * Company or project name * Intended use case and target audience * Expected usage volume * Desired persona characteristics The Curve Labs team reviews applications, typically within 2-5 days. After approval, the team schedules a 30-minute onboarding call to discuss your use case, craft a custom persona, define persona traits and communication style, whitelist your email for Playground access, and provide your unique `personaId`. After onboarding, create API keys in one of these ways: * Use `/keys` in [Playground](https://playground.curvelabs.org) for the browser UI * Run `thinkfeel login --persona-id YOUR_THINKFEEL_PERSONA_ID` for standalone CLI profile setup * Install the ThinkFeel Plugin for Codex or Claude Code from [CLI + Agents](/cli-agents) for agent-managed env-file setup ## Install the SDK and CLI ```bash theme={null} npm i @curvelabs.org/thinkfeel ``` ## Send your first request ```bash theme={null} curl -X POST https://playground.curvelabs.org/api/v1/generate \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY_HERE" \ -d '{ "personaId": "YOUR_PERSONA_ID", "messages": [ { "role": "user", "content": "Hello!" } ] }' ``` ## What beta includes Persona design is part of onboarding. Personas are designed with explicit boundaries and safety behavior. Beta pricing stays close to the cost of the underlying models. Beta users get direct engineering support. Ready to build? Start from [Authentication](/authentication), then choose either the ThinkFeel [`/generate`](/api-reference/generate) endpoint or the OpenAI-compatible [`/completions`](/api-reference/completions) endpoint. # SDK examples Source: https://docs.curvelabs.org/sdk-examples Generate ThinkFeel replies from JavaScript, TypeScript, Python, Ruby, and Go REST clients. These direct REST examples call `https://playground.curvelabs.org/api/v1/generate` with `THINKFEEL_API_KEY` and `THINKFEEL_PERSONA_ID`. ```javascript theme={null} const axios = require("axios"); async function generateResponse(messages, includeVariations = false) { try { const response = await axios.post( "https://playground.curvelabs.org/api/v1/generate", { personaId: process.env.THINKFEEL_PERSONA_ID, messages: messages, includeVariations: includeVariations, }, { headers: { "Content-Type": "application/json", "x-api-key": process.env.THINKFEEL_API_KEY, }, } ); return response.data; } catch (error) { console.error("Error:", error.response?.data || error.message); throw error; } } const messages = [ { role: "user", content: "Hey! What do you think about AI?" }, ]; generateResponse(messages).then((data) => { console.log("AI Response:", data.result.finalReply); }); ``` ```typescript theme={null} interface TextPart { type: "text"; text: string; } interface Message { role: "user" | "assistant" | "system" | "developer"; content: string | TextPart[]; timestamp?: number | string; createdAt?: number | string; created_at?: number | string; } interface GenerateResponse { status: "success"; rateLimits?: Array<{ limit: string; remaining: number | null }>; result: { finalReply: string; chunks: string[]; replyChoices?: string[]; }; } class ThinkFeelClient { private apiKey: string; private baseUrl = "https://playground.curvelabs.org/api/v1"; constructor(apiKey: string) { this.apiKey = apiKey; } async generate( personaId: string, messages: Message[], includeVariations = false ): Promise { const response = await fetch(`${this.baseUrl}/generate`, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": this.apiKey, }, body: JSON.stringify({ personaId, messages, includeVariations, }), }); if (!response.ok) { throw new Error(`API Error: ${response.status}`); } return response.json(); } } ``` ```python theme={null} import os import requests class ThinkFeelAPI: def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://playground.curvelabs.org/api/v1" def generate(self, persona_id: str, messages: list, include_variations: bool = False): headers = { "Content-Type": "application/json", "x-api-key": self.api_key } request_body = { "personaId": persona_id, "messages": messages, "includeVariations": include_variations } response = requests.post( f"{self.base_url}/generate", json=request_body, headers=headers ) response.raise_for_status() return response.json() api = ThinkFeelAPI(api_key=os.environ.get("THINKFEEL_API_KEY")) persona_id = os.environ.get("THINKFEEL_PERSONA_ID") messages = [ {"role": "user", "content": "What's your favorite thing to do?"} ] result = api.generate(persona_id=persona_id, messages=messages) print(f"AI: {result['result']['finalReply']}") ``` ```ruby theme={null} require "net/http" require "json" require "uri" class ThinkFeelAPI def initialize(api_key) @api_key = api_key @base_url = "https://playground.curvelabs.org/api/v1" end def generate(persona_id, messages, include_variations: false) uri = URI("#{@base_url}/generate") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri.path) request["Content-Type"] = "application/json" request["x-api-key"] = @api_key request.body = { personaId: persona_id, messages: messages, includeVariations: include_variations }.to_json response = http.request(request) JSON.parse(response.body) end end api = ThinkFeelAPI.new(ENV["THINKFEEL_API_KEY"]) persona_id = ENV["THINKFEEL_PERSONA_ID"] messages = [ { role: "user", content: "What do you think about art?" } ] result = api.generate(persona_id, messages) puts "AI: #{result["result"]["finalReply"]}" ``` ```go theme={null} package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) type Message struct { Role string `json:"role"` Content string `json:"content"` } type GenerateRequest struct { PersonaID string `json:"personaId"` Messages []Message `json:"messages"` IncludeVariations bool `json:"includeVariations,omitempty"` } type ThinkFeelClient struct { APIKey string BaseURL string } func NewThinkFeelClient(apiKey string) *ThinkFeelClient { return &ThinkFeelClient{ APIKey: apiKey, BaseURL: "https://playground.curvelabs.org/api/v1", } } func (c *ThinkFeelClient) Generate(personaID string, messages []Message) error { reqBody := GenerateRequest{ PersonaID: personaID, Messages: messages, } jsonData, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", c.BaseURL+"/generate", bytes.NewBuffer(jsonData)) req.Header.Set("Content-Type", "application/json") req.Header.Set("x-api-key", c.APIKey) client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) return nil } ``` # Support and feedback Source: https://docs.curvelabs.org/support Get help with ThinkFeel API integration issues. Curve Labs supports beta users directly. You can expect a response within 24 hours on weekdays. ## What to include Include the following when reporting an issue: 1. Your API key prefix, first 8 characters only 2. Timestamp of the issue 3. Request and response examples with sensitive data removed 4. Error messages or unexpected behavior 5. What you already tried Use the Curve Labs support form for API, onboarding, and billing questions. # Use cases Source: https://docs.curvelabs.org/use-cases Common product patterns for ThinkFeel integrations. Build support chatbots that understand tone and emotion, then respond with empathy and useful next steps. Create companion applications for mental wellness with warm, validating, wellness-only personas and clear escalation paths. Develop interactive storytelling or roleplay experiences with immersive characters. Build conversational language learning tools with encouraging and adaptive personas. If your use case needs a specific voice, safety boundary, or domain context, include that in your [request access](https://curvelabs.org/request-api-access) application.