GreenPT Docs

Mangrove Profiles

URL-addressed request presets — a pinned model and stored instructions behind a plain OpenAI request body.

POST

A Mangrove profile is a request preset stored with your account: a model choice plus a set of instructions, addressed by its own URL. Sending a chat completion to

POST /v1/agent-profiles/{slug}/chat/completions

applies the profile server-side — the pinned model is written onto the request and the stored instructions join the system message. The body stays the plain OpenAI chat-completion contract, so a thin client — a shell alias, a phone automation, a no-code tool that only knows "OpenAI-compatible" — sends nothing but messages.

Not the same as Mangrove runs

Mangrove runs are runs that work through a task with web search, document analysis, or transcription. A Mangrove profile changes nothing about how a request is executed — it is a stored configuration for a regular chat completion, and that is all.

Calling a profile

The endpoint ends in /chat/completions, so a stock OpenAI SDK needs no request changes at all: point its base URL at the profile and the SDK appends the rest. Authentication is your API key, as on every endpoint.

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["GREENPT_API_KEY"],
    base_url="https://api.greenpt.ai/v1/agent-profiles/support-triage",
)

client.chat.completions.create(
    model="",  # the profile pins the model; "" satisfies the SDK
    messages=[{"role": "user", "content": "Customer says the export hangs."}],
)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.GREENPT_API_KEY,
  baseURL: 'https://api.greenpt.ai/v1/agent-profiles/support-triage',
});

await client.chat.completions.create({
  model: '', // the profile pins the model; '' satisfies the SDK
  messages: [{ role: 'user', content: 'Customer says the export hangs.' }],
});
curl https://api.greenpt.ai/v1/agent-profiles/support-triage/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{ "role": "user", "content": "Customer says the export hangs." }]
  }'

Streaming works as on the plain endpoint — set "stream": true and read the streamed response as usual.

Profiles are addressed by URL only. The request body never names one: an agent body field is not part of the contract, so — on this endpoint and on plain /v1/chat/completions alike — it travels to the upstream model provider and is rejected there like any other unknown parameter.

The profile pins the model

The model parameter has three accepted forms, because the profile owns the choice:

  • omitted — the usual form for raw HTTP clients;
  • "" — satisfies SDKs that require the parameter;
  • exactly the pinned model — a redundant repeat is fine.

Any other value is a contradiction, and the request fails with a 400 naming the pinned model rather than silently overriding either side:

The agent profile pins the model; omit "model", send "", or send "gemma4".

How a profile is applied

  1. Resolve — the slug is matched against your own profiles, exactly and case-sensitively. Profiles are strictly personal: there is no organisation or GreenPT catalog, and nobody else's profile is reachable through your key. A slug that does not match an enabled profile of yours fails the request with a 404.
  2. Pin — the profile's model is written onto the request. Whether that model id is servable is judged afterwards, exactly as if you had sent it yourself.
  3. Inject — the stored instructions join the request's system message, wrapped in the same fenced block as skills: guidance you chose for the request, subordinate to the instructions outside it. A request without a system message gets one holding the block.
  4. Bill — the injected block's tokens are input tokens like any others, included in the usage the response reports; the X-Agent-Profile-Injected-Tokens header tells you exactly how many.

The skills request field keeps working on this endpoint as it does on the plain one — a profile fixes the model and base instructions, and a skill can still be named per request on top.

Response headers

Responses from the profile endpoint carry three headers, on streaming and non-streaming responses alike:

HeaderMeaning
X-Agent-ProfileThe applied profile's slug.
X-Agent-Profile-ModelThe model the profile pinned onto the request.
X-Agent-Profile-Injected-TokensTokens the injected block added to your prompt, wrapper included.

Managing profiles

Profiles are created and maintained at /v1/agent-profiles, authenticated with your API key. Every profile you can see is your own.

The profile object

FieldTypeDescription
idstringUnique identifier, used in the management routes.
slugstringThe URL segment that addresses the profile.
modelstringThe model pinned onto every completion through the profile.
instructionsstringThe instructions injected when the profile is applied. Detail and write responses only.
enabledbooleanWhether the profile's completion endpoint resolves.
createdAtstringISO 8601 timestamp.
updatedAtstringISO 8601 timestamp.

List profiles

GET /v1/agent-profiles

Returns { "agentProfiles": [...] } with your profiles, enabled or not, sorted by slug. List entries omit instructions; fetch a profile by id for the full object. The list is not paginated.

Get a profile

GET /v1/agent-profiles/{id}

Returns the full profile object, including instructions.

Create a profile

POST /v1/agent-profiles
FieldTypeRequiredDescription
slugstringYesStarts with a letter or digit; letters, digits, hyphens, underscores; max 64 characters.
modelstringYesAny model id, max 128 characters.
instructionsstringYes1 to 20,000 characters. Markdown welcome — it reaches the model as written.

Returns 201 with the profile object. A profile is enabled from the moment it is created. The model is accepted as written and judged for servability per request, so a profile may hold an id before it is available — completions through the profile fail until it is, then work without a profile edit.

curl https://api.greenpt.ai/v1/agent-profiles \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "support-triage",
    "model": "gemma4",
    "instructions": "Classify the message as bug, question, or feature request. Answer with the label, one sentence of reasoning, and a suggested reply."
  }'

Update a profile

PATCH /v1/agent-profiles/{id}

Accepts any of slug, model, instructions, and enabled — at least one. Returns 200 with the updated object. Note that changing slug changes the profile's URL: clients addressing the old slug get a 404.

Delete a profile

DELETE /v1/agent-profiles/{id}

Returns 204. The profile disappears from your list and its endpoint answers 404, and the slug stays reserved to your account — creating another profile under it answers 409. To retire a profile you might want back, set enabled to false instead; a disabled profile stays listed and editable while its endpoint answers 404.

Errors

Error responses on profile routes are plain text, not JSON.

StatusWhenBody
400The body's model contradicts the pinned oneThe agent profile pins the model; omit "model", send "", or send "<model>".
400A create or update body fails validationInvalid agent profile: followed by one line per issue.
401Missing or invalid API keyUnauthorized
404The slug does not resolve to an enabled profile of yoursUnknown agent profile "<slug>".
404The id does not exist or is not yoursAgent profile not found
409The slug is already taken among your profilesYou already have an agent profile named "<slug>".
503Mangrove profiles are not switched on in this environmentAgent profiles are not enabled

A 404 is deliberately uninformative: a disabled, deleted, or never-created slug all answer the same way, so a slug never reveals whether it exists in a state you cannot use. The 503 is answered before authentication; on completions, every other error follows authentication, credit, and rate-limit checks, so their status codes take precedence.

Limits

WhatLimit
Profiles per request1 — the URL names it
Slug64 characters
Model id128 characters
Instructions20,000 characters

On this page