Developers

Quickstart

Make your first call to the Developer API the desktop app serves on your PC. Nothing here goes through a Genisys server; the API listens on 127.0.0.1 only.

  1. Enable the local API. In the Genisys desktop app, open the Developer console and turn on the local API. It is off until you do, and listens on http://127.0.0.1:4319 by default (the port can be changed there).
  2. Create a test key. In the console, create an API key in test mode and give it only the scopes you need (for this guide: projects:read, runs:write, runs:read, plugins:invoke). Optionally limit it to projects, and set a per-minute limit and daily or monthly token budgets. Test keys start with gsk_test_; their runs are marked test. Copy the secret when it is shown and keep it like a password.
  3. Call the API. Every request sends Authorization: Bearer <key>.

With curl

List the projects your key may use:

export GENISYS_KEY=gsk_test_…   # your test key

curl http://127.0.0.1:4319/v1/projects \
  -H "Authorization: Bearer $GENISYS_KEY"

Start an agent run and wait for it to finish. The Idempotency-Key header is optional (up to 100 characters). Runs count against the key's token budget.

curl http://127.0.0.1:4319/v1/runs \
  -X POST \
  -H "Authorization: Bearer $GENISYS_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-1" \
  -d '{ "projectId": "<a project id from /v1/projects>", "prompt": "Summarise the open tasks." }'

Invoke a plugin tool (test keys can call draft, preview and production plugins):

curl http://127.0.0.1:4319/v1/plugins/word-tools/invoke \
  -X POST \
  -H "Authorization: Bearer $GENISYS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tool": "word_count", "input": { "text": "hello plugin world" } }'

From JavaScript

The @genisys/sdk package (packages/sdk in the Genisys repository) is not on npm yet. This dependency-free client covers every operation in the API reference; copy it into your project.

// genisys.mjs: a small client for the local Developer API (Node 22+ or any modern browser runtime).
const BASE = process.env.GENISYS_URL ?? 'http://127.0.0.1:4319';
const KEY = process.env.GENISYS_KEY; // gsk_test_… or gsk_live_…; never commit it

async function call(method, path, body, headers = {}) {
  const response = await fetch(BASE + path, {
    method,
    headers: { authorization: `Bearer ${KEY}`, ...(body ? { 'content-type': 'application/json' } : {}), ...headers },
    body: body ? JSON.stringify(body) : undefined,
  });
  const json = await response.json();
  if (!response.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
  return json;
}

export const genisys = {
  listProjects: () => call('GET', '/v1/projects'),
  createRun: (projectId, prompt, idempotencyKey) => call('POST', '/v1/runs', { projectId, prompt }, idempotencyKey ? { 'idempotency-key': idempotencyKey } : {}),
  getRun: (id) => call('GET', `/v1/runs/${encodeURIComponent(id)}`),
  getUsage: () => call('GET', '/v1/usage'),
  listPlugins: () => call('GET', '/v1/plugins'),
  invokePlugin: (id, tool, input) => call('POST', `/v1/plugins/${encodeURIComponent(id)}/invoke`, { tool, input }),
};

// Example
const { data: projects } = await genisys.listProjects();
const run = await genisys.createRun(projects[0].id, 'Summarise the open tasks.', 'quickstart-1');
console.log(run.status, run.output, run.usage);

When a call fails

Errors come back as { "error": { "code", "message" } }. A missing or revoked key is unauthorized; a missing scope or a project outside the key's limit is forbidden; a spent budget is budget_exceeded and too many requests in a minute is rate_limited. See all error codes.

Next: write a plugin or try one in the playground.