Quickstart

From an API key to an agent's first answer, then to events pushed to your server. You create a workspace, give it a model key, publish a small agent called hello, run it once, and register a webhook endpoint. Every step is one or two curl commands.

What you need

1. Create an API key

Sign up at https://app.forgeling.io/console with GitHub, Google or a verified email, enter your beta invite code and accept the beta terms. Signing up creates your app.

Then request approval in the console. Forgeling approves every app before it can run anything. Until yours is approved, everything below works except starting a run: POST /v1/workspaces/{ws}/runs answers 403 approval_required. You can do steps 1 to 4 and step 6 while you wait.

Under Keys, create a key with these scopes:

Scope Used for
workspaces:write Creating the workspace (step 2).
credentials:write Storing its model key (step 3).
bundles:write Publishing hello (step 4).
bundles:read Checking that the version is ready (step 4).
runs:write Starting and completing the run (step 5).
runs:read Reading the run back (step 5).
events:read Reading the run's events (step 5).
webhooks:write Registering and testing a webhook endpoint (step 6).

A write scope does not imply read: a key with runs:write alone can start a run but cannot read it back. Scopes lists them all.

The key is shown once, when you create it. Store it in your server's secret store, never in a browser, a mobile app or a repository, and put it in your shell for the commands below:

export FORGELING_API_KEY=fgk_…

Every call sends it as a bearer token, -H "Authorization: Bearer $FORGELING_API_KEY".

2. Create a workspace

A workspace holds one of your customers: their model key, their runs and their events. Give it your own id for that customer as external_id.

curl https://api.forgeling.io/v1/workspaces \
  -H "Authorization: Bearer $FORGELING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_id": "quickstart", "name": "Quickstart"}'

The answer is the workspace, 201 the first time. Sending the same external_id again answers 200 with the same workspace, so this call is safe to repeat. Keep its id:

export WS=ws_…

A workspace is a record, not a machine: it costs nothing until a run starts in it.

3. Store the model credential

Runs use the workspace's own Anthropic key, never one of Forgeling's. Replace sk-ant-… with the key:

curl -X PUT "https://api.forgeling.io/v1/workspaces/$WS/model_credential" \
  -H "Authorization: Bearer $FORGELING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "anthropic_api_key", "api_key": "sk-ant-…"}'

Forgeling checks the key with one small Anthropic call and answers "status": "valid" with its last four characters. A key Anthropic refuses is 422 credential_invalid. The key itself is never returned.

The key is readable by the agent inside every run sandbox of the workspace, and by any code the agent runs. Use a spend-limited Anthropic workspace key, one per customer, so a leaked key can spend only what you allowed. Your org's Anthropic key on the security page has the details.

4. Publish the hello agent

An agent definition is a named, versioned bundle. The simplest way to publish one is an inline spec: a model, instructions, and the tools the agent may use.

curl https://api.forgeling.io/v1/bundles/hello/versions \
  -H "Authorization: Bearer $FORGELING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "version": "1.0.0",
    "spec": {
      "model": "claude-sonnet-4-5",
      "instructions": "You are a friendly assistant. Answer in one or two sentences.",
      "tools": {"allow": []}
    }
  }'

An empty tools.allow list gives hello no tools: it can only answer. The answer is 202 with "status": "validating". A few seconds later the version is ready (or rejected, with errors); check it with GET /v1/bundles/hello/versions/1.0.0. The bundle.version_ready and bundle.version_rejected events say the same.

Versions are immutable. Publishing 1.0.0 again answers 409 bundle_version_exists; to change the agent, publish 1.0.1. Agent definitions covers every field.

5. Start a run and read its events

A run is one agent in its own sandbox. Start it with initial_turn, its first input:

curl "https://api.forgeling.io/v1/workspaces/$WS/runs" \
  -H "Authorization: Bearer $FORGELING_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-hello-1" \
  -d '{
    "definition": {"bundle": "hello", "version": "1.0.0"},
    "size": "small",
    "approvals": {"mode": "deny"},
    "budget": {"max_cost_usd": 1},
    "initial_turn": {
      "input": [{"type": "text", "text": "Say hello, and name one thing you can help with."}]
    }
  }'

The answer is 202 with the run, "status": "queued", and its first turn as turn. Keep the run's id:

export RUN=run_…

If the answer is an error instead, its code says why: 403 approval_required until your app is approved, 422 bundle_version_unavailable while hello@1.0.0 is not ready, or 409 credential_missing without a valid model key.

The run goes through run.queued, run.provisioning, run.ready and run.running, the turn through turn.started and turn.completed, and then the run waits for more input with run.idle. Read its events:

curl "https://api.forgeling.io/v1/runs/$RUN/events" \
  -H "Authorization: Bearer $FORGELING_API_KEY"

The answer lists the run's events in stream.seq order. Read again until the list ends with run.idle; starting the sandbox takes a little while. The turn.completed event carries the agent's answer in data.output.text, and its usage, cost_usd included. GET /v1/runs/{run} shows the run's status and its usage so far. The event catalog describes every event type.

An idle run can take more turns (POST /v1/runs/{run}/turns). This one is done, so complete it:

curl -X POST "https://api.forgeling.io/v1/runs/$RUN/complete" \
  -H "Authorization: Bearer $FORGELING_API_KEY"

Completing tears the sandbox down. The run's last event is run.completed, with usage_total.

6. Get events pushed to you

Polling works, but a webhook endpoint gets each event as it happens. Register an HTTPS URL of yours:

curl https://api.forgeling.io/v1/webhook_endpoints \
  -H "Authorization: Bearer $FORGELING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/webhooks/forgeling"}'

The answer is the endpoint, with its signing secret, secret (whsec_…). The secret is shown once: store it next to your API key. Keep the endpoint's id, and ask for a test delivery:

export ENDPOINT=whe_…

curl -X POST "https://api.forgeling.io/v1/webhook_endpoints/$ENDPOINT/test" \
  -H "Authorization: Bearer $FORGELING_API_KEY"

Your URL receives a signed ping: a POST whose body is one event envelope, with the headers webhook-id, webhook-timestamp and webhook-signature. Check the signature with the secret before you trust a delivery; Verify every delivery has a function to copy, in Python and in TypeScript.

The endpoint gets the default subscription, so the next run you start reports its progress there.

Next