GreenPT Docs

Quickstart

Get an API key, send your first Mangrove run, and try it in the playground.

Your first run

  1. First, create an API key. Runs are paid from your API credits; see Billing & limits.
  2. Send a screenshot of your phone's Screen Time summary and ask what to cut back on:
curl -X POST https://api.greenpt.ai/v1/agents/runs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "question=What should I cut back on?" \
  -F "file=@screen-time.png"

Voila! Poll or stream the returned agentId for your answer.

Playground

Try it without leaving this page. Save your API key, ask a question, and optionally attach an image, a document, or a recording — or paste a link to one. The run picks up whichever tool the question needs. Events stream in live, exactly as they would over SSE in your own client.

Each Run Mangrove press is one run, standing on its own — the playground does not thread your questions together, so a follow-up here needs the earlier context restated in the question, exactly as it would in your own client. See One run, one exchange.

Mangrove is in beta; the playground tells you when it is not switched on for this environment.

Loading API key…
Loading Mangrove…

End-to-end example

Create a run, then stream it until done:

AGENT_ID=$(curl -s -X POST https://api.greenpt.ai/v1/agents/runs \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"question": "What does GreenPT offer?"}' | jq -r .agentId)

curl -N https://api.greenpt.ai/v1/agents/runs/$AGENT_ID/stream \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: text/event-stream"
const BASE = 'https://api.greenpt.ai';
const KEY = process.env.GREENPT_API_KEY;

const created = await fetch(`${BASE}/v1/agents/runs`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${KEY}` },
  body: JSON.stringify({ question: 'What does GreenPT offer?' }),
});
const { agentId } = await created.json();

const stream = await fetch(`${BASE}/v1/agents/runs/${agentId}/stream`, {
  headers: { Accept: 'text/event-stream', Authorization: `Bearer ${KEY}` },
});

const decoder = new TextDecoder();
let buffer = '';
for await (const chunk of stream.body) {
  buffer += decoder.decode(chunk, { stream: true });
  let i;
  while ((i = buffer.indexOf('\n\n')) !== -1) {
    const raw = buffer.slice(0, i);
    buffer = buffer.slice(i + 2);
    const data = raw
      .split('\n')
      .filter((line) => line.startsWith('data:'))
      .map((line) => line.slice(5).trim())
      .join('\n');
    if (!data) continue;
    const event = JSON.parse(data);
    // `text` is progress and repeats across steps, so it goes to stderr;
    // `finalText` is the answer. See "Reading a stream without duplicating
    // the answer" above.
    if (event.type === 'text') process.stderr.write(event.text);
    if (event.type === 'done') console.log(event.finalText);
    if (event.type === 'input_required') console.log('Needs:', event.expected);
    if (event.type === 'error') console.error('Failed:', event.message);
  }
}
import json
import os
import sys

import requests

BASE = "https://api.greenpt.ai"
KEY = os.environ["GREENPT_API_KEY"]
headers = {"Authorization": f"Bearer {KEY}"}

created = requests.post(
    f"{BASE}/v1/agents/runs",
    headers={**headers, "Content-Type": "application/json"},
    json={"question": "What does GreenPT offer?"},
)
agent_id = created.json()["agentId"]

with requests.get(
    f"{BASE}/v1/agents/runs/{agent_id}/stream",
    headers={**headers, "Accept": "text/event-stream"},
    stream=True,
) as response:
    for line in response.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        event = json.loads(line[len("data:"):].strip())
        # `text` is progress and repeats across steps, so it goes to stderr;
        # `finalText` is the answer. See "Reading a stream without duplicating
        # the answer" above.
        if event["type"] == "text":
            print(event["text"], end="", file=sys.stderr, flush=True)
        elif event["type"] == "done":
            print(event["finalText"])
        elif event["type"] == "input_required":
            print("Needs:", event["expected"])
        elif event["type"] == "error":
            print("Failed:", event["message"])

Polling instead of streaming works the same way: call GET /v1/agents/runs/{agentId} on an interval until status is succeeded, failed, or awaiting_input.

On this page