Minds Team

Minds API Integration Guide for AI Agents

Agent-oriented guide to discovering, authenticating, safely calling, retrying, polling, and presenting Minds v1 API workflows.

This guide is the operating contract for an AI agent that calls the Minds v1 REST API. It complements the OpenAPI document, complete endpoint catalog, and domain walkthroughs.

Choose REST or MCP

NeedPreferWhy
Generate a typed SDK, run a backend integration, or control HTTP detailsv1 REST APIStable resource URLs, response envelopes, streaming, and durable job endpoints
Let ChatGPT, Claude, Cursor, or another compatible assistant select research toolsMCPProtocol-native tool schemas, annotations, OAuth, widgets, and presentation contracts
Build a long-running service that resumes after process restartsv1 REST APIPersist run, Study, draft, and export IDs in your own job state
Run research interactively from a user conversationMCPTool descriptions encode routing, confirmation, and safe presentation behavior

Both surfaces call the same v1 application boundaries for supported research actions. Do not combine REST and MCP in the same logical operation unless you have an explicit reason and a stable resource ID.

Discovery checklist

Read these resources before generating code or planning calls:

  1. https://getminds.ai/_openapi.json — live OpenAPI 3.1 document for routes with detailed operation metadata.
  2. https://getminds.ai/docs/api/reference — complete v1 route catalog, including routes whose detailed OpenAPI schemas are still being expanded.
  3. https://getminds.ai/docs/api/errors — error envelope, plan limits, and retry behavior.
  4. https://getminds.ai/llms.txt and https://getminds.ai/llms-full.txt — agent-oriented documentation discovery and consolidated reference text.
  5. https://getminds.ai/mcp/agents — use this instead when your host supports MCP tools.

Do not infer that a route is unavailable merely because it is not yet present in the generated OpenAPI document. The endpoint catalog is the completeness authority; the OpenAPI document is the schema authority for operations it includes.

Authentication and secret handling

Send a personal Minds API key as a bearer token:

Authorization: Bearer minds_…

Agent rules:

  • Read the key from a secret manager or environment variable. Never place it in prompts, source code, URLs, logs, traces, or error messages.
  • Use separate keys for development and production.
  • Treat the value returned by POST /api/v1/api-keys as write-only: it is shown once.
  • Do not let an autonomous agent rotate or revoke the key it is currently using.
  • On 401, stop and request credential repair. Do not repeatedly retry.
  • On 403, do not disguise an access-policy failure as “not found.” Explain that the authenticated account lacks access.

Stable request wrapper

Centralize authentication, JSON handling, timeouts, and error parsing:

const MINDS_BASE_URL = 'https://getminds.ai/api/v1'

type MindsError = {
  statusCode?: number
  statusMessage?: string
  message?: string
  data?: unknown
}

async function mindsRequest<T>(
  path: string,
  init: RequestInit = {},
): Promise<T> {
  const response = await fetch(`${MINDS_BASE_URL}${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.MINDS_API_KEY}`,
      ...(init.body ? { 'Content-Type': 'application/json' } : {}),
      ...init.headers,
    },
    signal: init.signal ?? AbortSignal.timeout(120_000),
  })

  const contentType = response.headers.get('content-type') || ''
  const payload = contentType.includes('application/json')
    ? await response.json()
    : await response.text()

  if (!response.ok) {
    const error = payload as MindsError
    throw new Error(
      `Minds ${response.status}: ${error.message || error.statusMessage || response.statusText}`,
    )
  }

  return payload as T
}

Use the apex form (https://getminds.ai/api/v1) if your infrastructure does not follow same-origin 307 redirects for API-subdomain GET requests.

Plan before mutating

Classify each proposed call:

ClassExamplesAgent behavior
Read-onlyList/read resources, status, analytics, methodsMay call when needed to answer the request
Reversible creation/updateCreate a private draft, update a nameState the intended target; preserve returned IDs
Costly executionAsk an Audience, run a Study, retrain, regenerateEnsure it matches the user's request and avoid duplicate calls
Public exposureEnable link sharingRequire explicit intent; explain what becomes public
DestructiveDelete Minds, Audiences, Studies, chats, Formations, draftsObtain explicit confirmation of exact IDs immediately before the call
Credential controlMint/revoke API keysKeep outside autonomous research flows

Never enable isLinkSharingEnabled merely to make a result convenient to access. Private is the default.

Use IDs as durable state

Names are suitable for user interaction, but IDs are the integration contract. Persist:

  • sparkId after Mind creation;
  • audienceId after Audience creation;
  • studyId after Study creation;
  • draftPlanId and revision during research planning;
  • studyId or runId during execution;
  • jobId for exports;
  • itemId for knowledge ingestion;
  • draftId and expectedRevision for sidebar Study drafts.

Do not re-list by fuzzy name after a successful create response. Doing so can select the wrong resource when names are duplicated.

Asynchronous operations

Several operations return before work is complete.

Start operationPersistPoll/read
Create MindsparkIdGET /minds/{mindId}/training
Create grounded AudienceaudienceIdGET /audiences/{id}/progress
Add file/link knowledgeitemIdGET /minds/{mindId}/knowledge/{itemId}/status
Ask a Study in queued moderunIdGET /runs/{runId} and /events
Run confirmed multi-question blockrunIdGET /studies/{studyId}/research-runs/{runId}
ExportjobIdentity-specific export-status, then export-download

Recommended polling behavior:

  1. Honor Retry-After when returned.
  2. Otherwise start at 1–2 seconds and exponentially back off to 10–15 seconds.
  3. Add jitter when many jobs run concurrently.
  4. Persist the last event cursor for /runs/{runId}/events.
  5. Stop on terminal success, failure, cancellation, or plan_limited.
  6. Set a workflow-level deadline; a client timeout does not prove the server operation failed.

Idempotency and retries

  • Retry GET requests after transient 429, 502, 503, or 504 responses using bounded exponential backoff.
  • Retry a mutation only when the endpoint documents idempotency or you supplied a stable idempotency key.
  • create_audience_from_brief derives an idempotency key from its arguments. If the initial call times out before returning an ID, retry its exact arguments to recover the owned operation and current review or accepted Audience. Once an operation ID is available, resume that operation instead of submitting the brief again. A review is not creation or consent: confirm the unchanged accepted draft or grounding snapshot and checksum before materialization.
  • run_study_questions supports an explicit stable idempotency key through MCP; REST callers should preserve the confirmed draft ID/revision and returned Study ID.
  • Optimistic-concurrency failures on Study drafts require a fresh read and human/agent reconciliation. Do not overwrite with a guessed revision.
  • Never retry destructive calls merely because the client did not receive the response. Read the resource first to determine whether deletion already succeeded.

Direct questions versus guided Studies

Use this routing table:

User requestRoute
One direct question to an existing StudyPOST /studies/{studyId}/ask
Knowledge-only durable direct runPOST /studies/{studyId}/runs
Multiple questions, a broad objective, an asset audit, structured evidence outputs, or an explicit methodPlan → confirm → Study lifecycle
Export existing evidencePOST /studies/{studyId}/export
Show existing evidence differentlyRead status/summary/analytics; do not recruit a new run

The guided lifecycle is:

POST research-plans/preview
  -> present the exact draft and every confirmation question
  -> revise the same draft if the user changes or answers anything
  -> receive explicit confirmation of the exact revision
  -> POST studies with that draft ID and revision
  -> poll GET studies/{studyId}
  -> GET or POST summary

Planning is non-executing. Never claim that research has started after a preview call.

Method availability

Call GET /api/v1/research-methods before promising a named method. Treat fields as follows:

  • preparesQuestionsAtExecution: true — the method generates deterministic questions and response contracts from its configuration at execution; saved template questions are not the full executed instrument.
  • executable: true — the registered server adapter can run the method.
  • executable: false — the method may be represented or planned but is not an execution promise.
  • Advanced methods require explicit opt-in at execution time.
  • Preserve deterministic calculations returned by the Study endpoint; do not recompute them with an LLM.

File and URL inputs

  • Upload interactive browser files with multipart form data.
  • For autonomous agents, prefer public, short-lived signed, or Minds workspace-upload URLs.
  • Do not embed large binary files as base64 JSON.
  • Give every file a meaningful name and MIME type when known.
  • URLs may be rejected by SSRF and redirect guards even when they are syntactically valid.
  • Knowledge retrieval is bounded to 50 MB and a server timeout; split larger sources before ingestion.
  • For respondent datasets, preview segmentation before creating a representative cohort.

Error decisions

SignalMeaningAgent response
400 / validation detailsRequest does not satisfy the schemaCorrect the payload; do not retry unchanged
401Missing/invalid/expired credentialStop and repair authentication
403Authenticated but not allowedExplain access/ownership/plan boundary
404Resource is absent or not visibleVerify the persisted ID and account context
409Revision/idempotency/state conflictRead current state and reconcile
415Unsupported request media typeCorrect Content-Type or file form
429Rate or usage limitHonor Retry-After; distinguish rate limiting from plan_limited
plan_limited before executionNothing startedExplain the required plan/allowance change
status: plan_limited during a StudyPartial artifacts were preservedReport completed versus remaining questions; never call it complete
5xxTransient or server failureBounded retry for safe/idempotent calls, otherwise read state first

Result presentation

  • Preserve citations, source URLs, shared links, download links, and resource IDs exactly.
  • Clearly label synthetic responses and distinguish them from primary human research.
  • Report status as queued/running/partial/completed/failed based on returned fields, not elapsed time.
  • For categorical or multiselect results, preserve the server's aggregation semantics instead of forcing percentages to sum to 100 when multiple selections are allowed.
  • Do not invent missing Mind answers or fill incomplete Study artifacts.
  • Use the authenticated workspace link for the owner and a returned shared link only for external handoff.

Minimal autonomous Study example

const studies = await mindsRequest<{ data: Array<{ id: string; name: string }> }>(
  '/studies',
)

const study = studies.data.find(item => item.name === 'Launch research')
if (!study) throw new Error('Study not found')

const started = await mindsRequest<{ data: { runId: string } }>(
  `/studies/${study.id}/runs`,
  {
    method: 'POST',
    body: JSON.stringify({
      question: 'What are the strongest objections to this positioning?',
      sourcePolicy: 'knowledge_only',
    }),
  },
)

// Persist started.data.runId before polling.

Preflight checklist

Before a mutation, verify:

  • the authenticated workspace and plan context;
  • exact resource IDs and ownership/access;
  • whether the request is direct research or requires a confirmed plan;
  • whether sharing remains private;
  • whether a previous timed-out call may already have succeeded;
  • whether the operation consumes an allowance or triggers generation;
  • whether explicit confirmation is required.

After a mutation, persist returned IDs, poll the documented status endpoint, and present only terminal or explicitly partial results.

n8n workflows

For an n8n AI Agent, attach the Minds node as a tool and select a bounded Study operation. Store authentication in a Minds API credential, keep link sharing disabled unless publication is intended, and require separate review in Minds before research starts.

Purchase orchestration

This HTTP workflow does not imply checkout support inside every assistant. ChatGPT’s standard app rules currently exclude digital subscription and credit purchases; existing paid customers may use the research app. Do not advertise these billing tools or initiate a purchase through the ChatGPT app without explicit platform enablement. Other clients must permit the workflow and obtain buyer approval. See the OpenAI commerce rules.

Treat billing as a separate buyer-approved workflow. Begin with GET /api/v1/billing/catalog, choose an eligible subscription or response-credit pack, and save the buyer's decision before sending a checkout request. An existing subscriber who wants to change their plan should use Minds billing settings.

A response-credit request is small:

{ "kind": "response_credits", "priceId": "price_selected_by_buyer" }

Submit it to POST /api/v1/billing/checkout with one durable purchase identifier in Idempotency-Key. For subscription setup, collect legalAcceptance.termsAccepted and legalAcceptance.withdrawalConsent as explicit true values; the billing overview shows that request shape. Keep the purchase record together with the returned data.checkoutSessionId and data.url, and show the hosted URL without rewriting it.

Distinguish these outcomes in your workflow:

ObservationAgent action
Checkout URL returnedAsk the buyer to continue on Stripe; payment is still pending
Connection lost before acknowledgementResubmit the identical purchase with its saved key
409 conflict or reconciliation requiredInspect the existing purchase; do not replace its key to force another session
Signed Stripe confirmation receivedLet the existing webhook update entitlements or response credits

Handling a payable invoice

Use the HTTP payment client for POST /api/v1/billing/invoices/{invoiceId}/pay. The server verifies the buyer's ownership before returning a quote. Eligible invoices have collection_method: "send_invoice", remain open, use USD/EUR and owe at least 50 minor units. A subscription collected automatically is outside this direct-payment workflow.

Read the 402 response rather than inferring the payable total from a catalog price. MPP uses a Stripe shared payment token and needs the merchant's Business Network profile. Optional x402 settlement uses Base USDC for USD invoices, a configured facilitator and mppx route-bound credentials. Before signing, check that the challenge identifies the intended invoice and amount.

Keep wallet material out of the conversation and MCP input. With ordinary Minds bearer authentication, supply MPP in Payment-Authorization or x402 in PAYMENT-SIGNATURE. If your MPP library owns Authorization: Payment, put the Minds identity in Minds-Authorization: Bearer instead. This alternative is limited to invoice payment. Preserve the original payment credential after an uncertain response and stop on a reconciliation conflict.

Connecting an agent payment client

Minds MCP provides research and permitted purchase-orchestration tools. The buyer's payment client supplies payment authorization; connecting Minds MCP alone does not give an assistant a wallet or permission to spend. Connect both services to a client that permits the purchase workflow. Stripe's Link CLI can run as a separate MCP server and issue one-time shared payment tokens for MPP. The Stripe MPP guide documents sandbox tokens and the payment-client flow.

The buyer signs in to their own Link account and authorizes the connection. Check buyer eligibility before promising this path: the current Link CLI documentation limits wallet access to US and Canadian Link accounts. Merchant account eligibility is a separate check; owning a US Stripe business account does not make a German buyer eligible. Check the provider's current documentation when onboarding.

Request approval for the actual invoice amount and intended merchant, then let the client submit the one-time credential directly to the HTTP payment route. Link normally asks for purchase approval. Unattended spending requires a supported, explicitly configured authorization policy with an appropriate spending limit; do not infer such a policy from a connected wallet or a conversational instruction. Additional authentication can still be required. Payment credentials stay outside model-visible tool arguments and transcripts.

For a client whose MPP library uses Authorization: Payment, preserve the Minds identity through Minds-Authorization: Bearer. A client that cannot send this alternate header needs an adapter that keeps ordinary Minds bearer authentication and sends the payment credential in Payment-Authorization. Never replace the buyer's Minds identity with wallet identity.

For new Pay as you go workspaces, provide billingCountry when reading the catalog and starting response-credit checkout. Read the catalog again if the country changes; this selects the correct Stripe entity and currency. Response packs share one unit rate and fund the shared workspace response pool.

Example purchase journeys

For “buy 500 responses, then research our landing page,” read the catalog with the buyer’s billingCountry and obtain approval for the selected pack and checkout amount. Start hosted checkout with kind: "response_credits", the selected priceId, the same billingCountry and a durable idempotency key. Return the Stripe URL verbatim to the buyer. After Stripe confirms payment and signed fulfillment, verify the shared response balance before starting the separately approved research workflow. New Starter subscriptions and trials are retired; existing subscriptions remain manageable in Minds billing settings.

For an existing eligible response-credit invoice, send an authenticated POST /api/v1/billing/invoices/{invoiceId}/pay without a payment credential. Read the returned 402 quote, obtain the buyer-authorized MPP credential, and retry the same route with that credential. Require the successful payment response and receipt, and verify the resulting credit entitlement after signed Stripe webhook processing before resuming research. Do not substitute a catalog price for the invoice total or assume this route purchases arbitrary new subscriptions in one call.

Verification status

As of 3 October 2026, production payment discovery and an owned EUR-invoice MPP 402 challenge have been verified. A successful production MPP card purchase, receipt and entitlement activation have not yet been verified end to end. x402 settlement succeeded with test USDC in the sandbox, but Stripe's crypto PaymentIntent-recording preview activation remains pending; no successful production x402 purchase is claimed. Treat a valid discovery document or 402 challenge as negotiation, not proof of payment readiness or fulfillment. Revalidate the complete sandbox journey and an explicitly approved live purchase before advertising unattended purchasing.

Hosted ACP continuation

For a client that speaks ACP, bootstrap from /.well-known/acp.json and follow its REST base URL. Version 2026-04-17 accepts a single current Stripe price, currency and capabilities object. Subscription approval belongs in metadata; seat quantity applies to Team prices. Every POST carries a purchase idempotency key.

Your state machine should wait while continue_url is present. Empty update/complete requests only recheck Stripe state; they cannot submit payment details or accept terms for the buyer. Cancellation expires an open owned session. See the route reference for action paths and /openapi.json for payment-discovery metadata.

Hosted UCP continuation

Read /.well-known/ucp for the REST endpoint and supported checkout version 2026-08-25. Your platform must publish a compatible UCP profile and authenticate with a Minds OAuth metadata-document client whose HTTPS origin matches that profile. UCP operations require UCP-Agent: profile="https://your-platform.example/.well-known/ucp"; every write also requires a stable Idempotency-Key. This binding prevents an authenticated account from impersonating a different platform.

Create a checkout with POST /api/ucp/checkout-sessions:

{
  "line_items": [{ "item": { "id": "price_selected_by_buyer" }, "quantity": 1 }],
  "context": {
    "address_country": "DE",
    "minds": {
      "legalAcceptance": { "termsAccepted": true, "withdrawalConsent": true }
    }
  }
}

Use a current price from the authenticated billing catalog. The selected price determines currency; optional context.currency must match it. Quantity greater than one applies only to Team seats, and subscriptions require the explicit legal acknowledgements above. context.address_country is a provisional billing-country signal; stored account ownership and verified checkout details take precedence. The server owns prices and totals; requests must not supply an amount or payment instrument.

GET /checkout-sessions/{id} reads the authenticated owner’s current session. Return continue_url verbatim to the buyer while status is requires_escalation. PUT /checkout-sessions/{id} accepts the same line item and quantity as a refresh; requested cart or context changes return a recoverable message and leave the purchase intact. To change the purchase, cancel the old open checkout and create a new one with a new key. POST /checkout-sessions/{id}/complete accepts { "payment": {} } and rechecks Stripe’s payment state; POST /checkout-sessions/{id}/cancel expires an owned open session. Paths are relative to /api/ucp.

The profile advertises no UCP payment handlers because Stripe hosts buyer payment. A completed response includes an authenticated checkout permalink; signed Stripe webhooks still determine entitlement and credit fulfillment. An agent must not treat a continuation URL as proof of payment.

Budget-driven response purchases

For a request such as “spend up to €200 on research responses,” explain the quote and obtain approval before creating checkout. Read the buyer’s currency and custom source offer from the billing catalog, then submit amountMinor: 20000 with that source priceId and the billing country. At the current EUR rate this corresponds to 1,680 responses and a €199.92 charge.

Save the approved input alongside the purchase key in the private checkpoint. If a network timeout occurs, send the identical request again; a changed budget is a different purchase. Return the hosted URL for the buyer to finish payment, then verify the credited response pool before resuming research. This workflow uses response credits, with no separate cash wallet.

Pass includeInvoices: true to get_billing_catalog, or includeInvoices=true to GET /api/v1/billing/catalog, to include recent invoices under subscription.invoices. Only the billing owner or an authorized administrator can read that customer’s invoices; the default catalog omits invoice retrieval.