Developer API

Query available voices and avatars, create agents, and update their identity through HTTPS.

The npm client release is pending. Use the HTTPS endpoints below until the new version is published.

Embedding the proprietary npm client in another product requires written permission from Harvest AI under its license.

Account key

Sign in with Google, then create a developer key below. It controls every agent in your Harvest account. Store it server side. Agent meeting tokens are separate and only connect an agent to the MCP gateway.

Checking key status…

Query voices, avatars and backdrops

// Run on your server. Never expose the account key to an agent or browser.
async function harvest(path, init = {}) {
  const response = await fetch("https://tryharvest.ai/api" + path, {
    ...init,
    headers: { Authorization: "Bearer " + process.env.HARVEST_DEV_KEY,
      "Content-Type": "application/json", ...init.headers },
  });
  if (!response.ok) throw new Error("Harvest " + response.status + ": " + await response.text());
  return response.json();
}
const catalog = await harvest("/catalog/identities");
const voice = catalog.voices.find((v) => v.languages?.includes("ru") && v.gender === "female");
if (!voice) throw new Error("Requested voice unavailable");
const backdrop = catalog.backdrops.includes("grid") ? "grid" : "none";

The catalog returns public voice_preset and identity_id values. Developer-key creation requires an explicit listed voice; a later PATCH can omit voice_preset to keep the current voice.

Voice entries may include supported languages, gender, provider and tags. Filter the HTTPS catalog with ?locale=ru&gender=female&tag=local; locale matches the supported language, including regional forms, without promising an accent. Local voices include EN/RU previews and require an ordinary model with TTS; Live-1 uses its own voice. Selected voice IDs and backdrop slugs are validated again when you configure an agent.

Create and configure an agent

const requestKey = crypto.randomUUID(); // Persist before sending; reuse on retry.
const created = await harvest("/agents", { method: "POST",
  headers: { "Idempotency-Key": requestKey },
  body: JSON.stringify({
  display_name: "Researcher",
  identity_id: "cube",
  voice_preset: voice.voice_preset,
  color: "#ff6a45",
  backdrop_slug: backdrop,
  }),
});
const id = created.agent.agent_id;
await harvest("/agents/" + id + "/identity", { method: "PATCH",
  body: JSON.stringify({ avatar_slug: "aura", description: "Research meeting agent",
    persona: "Answer briefly.", intonation_preset: "confident" }),
});
const { agent } = await harvest("/agents/" + id);
if (agent.identity.voice_preset !== voice.voice_preset || agent.identity.avatar_slug !== "aura")
  throw new Error("Agent configuration did not round-trip");
// Give created.credential.token only to this agent's MCP runtime; it appears once.
// If lost, issue a replacement with POST /agents/:id/credentials.

The API accepts a 1–80 character name, six-digit hex color, catalog voice ID, catalog avatar and backdrop slug, optional description of at most three words, persona of at most 1,000 characters, and intonation neutral, confident, fast or emotional. Upload a custom account-owned avatar with POST /agents/:id/avatar: PNG only, at most 2 MB, 64–4096 pixels per side, and within 1% of square. Arbitrary image URLs are not accepted. Keep the developer key on your server and give only the one-time agent token to that agent's MCP runtime.

For a timed-out create request, retry with the same Idempotency-Key header. A duplicate returns 409 without the original one-time token. Read GET /agents to find the created agent and issue a new agent token if needed.

Developer keys allow 120 requests per minute per account; agent creation allows 30 requests per hour per account, including dashboard creates. A 429 response includes Retry-After in seconds.

To let an external agent choose its own settings, expose a server tool that derives the Harvest agent ID from its authenticated session. Check its requested voice, avatar and backdrop against a fresh catalog, PATCH only that ID, then GET the same ID and return the saved choices. On a stale or rejected choice, refresh the catalog and ask the agent to choose again. Never give the account developer key or a caller-supplied target agent ID to the model.

async function configureSelf(agentSession, choice) {
  const id = agentSession.harvestAgentId; // Set by your server, never by the model.
  const choices = await harvest("/catalog/identities");
  if (!choices.voices.some((v) => v.voice_preset === choice.voice_preset)
    || !choices.backdrops.includes(choice.backdrop_slug)
    || !choices.identities.some((a) => a.avatar_slug === choice.avatar_slug))
    throw new Error("Choice unavailable; refresh catalog and choose again");
  await harvest("/agents/" + encodeURIComponent(id) + "/identity", {
    method: "PATCH", body: JSON.stringify(choice),
  });
  return (await harvest("/agents/" + encodeURIComponent(id))).agent;
}

The same API is available at https://tryharvest.ai/api using Authorization: Bearer hvst_dev_.... Read GET /catalog/identities and GET /agents; create with POST /agents; edit with PATCH /agents/:id/identity. Account IDs in request bodies are ignored.

GET /sessions/:id/artifacts returns available transcript, spoken fragments, full summary, action items, chapters and an owned recording URL that expires in 15 minutes. Check availability; unfinished artifacts can be null. Generated spoken fragments labelled delivery: unverified are not proof of audible speech. Another account receives 404.

Webhook subscriptions accept your developer key or dashboard session. GET /webhooks lists them, POST /webhooks takes a public HTTPS endpoint and event names and returns the signing secret once, DELETE /webhooks/:id deactivates one, and GET /webhooks/:id/deliveries returns its delivery history. A caller-supplied account id is ignored. Manage up to two active endpoints in Webhook settings.

Deliveries contain event, idempotency_key, occurred_at, payload and signature. Verify with the hosted SDK's verifyWebhookSignature(envelope, secret), which matches Harvest's canonical JSON and HMAC-SHA256 base64 signature. Retries keep the same event time and idempotency key; acknowledge only after durable handling, and deduplicate successful processing. See the partner quickstart for receiver code.