API quickstart

Use Plaine’s agent API when you own the agent runtime and want to exchange messages with Plaine over HTTP.

Start in the Plaine dashboard:

  1. Open Agents and create an agent.
  2. Choose a delivery mode:
    • Pull for MCP clients, local runners, and agents that cannot receive public webhooks.
    • Push for webhook servers that can receive Plaine POSTs.
  3. Create an API key from the agent’s settings. Open API keys. Copy it immediately; Plaine only shows the key once.
  4. Add an agent public key before inviting other Plaine users to encrypted peer conversations.

Authenticate

Send the agent API key as either x-api-key or a Bearer token:

x-api-key: plane_xxx
Authorization: Bearer plane_xxx

Examples below use x-api-key.

export PLAINE_API_BASE=https://plaine.chat
export PLAINE_API_KEY=plane_xxx

Pull mode

Pull mode is the simplest shape for local agents. The agent creates or finds a conversation, sends messages into it, and polls for user replies.

Create or find a conversation with you, the agent owner, by label:

curl -s "$PLAINE_API_BASE/api/agent/conversations" \
  -H "x-api-key: $PLAINE_API_KEY" \
  -H "content-type: application/json" \
  -d '{"label":"local-dev"}'

Response:

{
  "conversationId": "conv_...",
  "label": "local-dev",
  "created": true
}

Send an agent message:

curl -s "$PLAINE_API_BASE/api/agent/conversations/conv_.../messages" \
  -H "x-api-key: $PLAINE_API_KEY" \
  -H "content-type: application/json" \
  -d '{"parts":[{"type":"text","text":"I need a decision before I continue."}]}'

Response:

{ "id": "msg_..." }

Ask for tool approval by sending a tool part with state: "approval-requested":

curl -s "$PLAINE_API_BASE/api/agent/conversations/conv_.../messages" \
  -H "x-api-key: $PLAINE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "parts": [
      {
        "type": "tool-shell",
        "toolCallId": "call_deploy_1",
        "state": "approval-requested",
        "input": { "command": "pnpm deploy:staging" }
      }
    ]
  }'

The peer’s decision returns as a normal user message part:

{
  "type": "data-tool-approval",
  "id": "approval_...",
  "data": {
    "toolCallId": "call_deploy_1",
    "approved": true,
    "reason": "optional short text"
  }
}

Resume the paused work only after you receive a matching data-tool-approval part with the same toolCallId.

Poll the inbox for user messages:

curl -s "$PLAINE_API_BASE/api/agent/conversations/conv_.../inbox?wait=25" \
  -H "x-api-key: $PLAINE_API_KEY"

Response:

{
  "messages": [
    {
      "id": "msg_...",
      "conversationId": "conv_...",
      "senderType": "user",
      "timestamp": "2026-05-13T12:00:00.000Z",
      "parts": [{ "type": "text", "text": "Use the safer migration." }]
    }
  ],
  "nextCursor": "msg_..."
}

Pass since=<message_id> on the next inbox request to receive only newer user messages. wait enables long-polling; Plaine caps a single wait at 30 seconds.

Push mode

Use push mode when your agent has a public webhook server. Plaine POSTs new user messages to your webhook, and your server replies through the same message endpoint. Use the conversationId from the webhook payload:

curl -s "$PLAINE_API_BASE/api/agent/conversations/conv_.../messages" \
  -H "Authorization: Bearer $PLAINE_API_KEY" \
  -H "content-type: application/json" \
  -d '{"parts":[{"type":"text","text":"Thanks, I will continue."}]}'

For push mode, always verify Plaine’s webhook signature before trusting the request. See Webhook signing.

Approval responses use the same message.new webhook envelope as text replies. Match message.parts[].data.toolCallId to the pending tool call before resuming the tool.