Developer API
Your Portail account, from your own code
Search your memory, read your connected apps, and act through them with one HTTPS call from your server.
Create a key in Portail under Settings > Developer API. Keys come with any paid plan.
Open PortailWhat it is, and what it isn't
The API reaches Portail features on your own account. It does not run language models and it does not sell model access, so calls never spend credits. If you want a model's answer, that happens in Portail itself.
Base URL
https://api.portail.cc/api/v1Authentication
Send the key as a bearer token. Call from your server only: requests carrying a browser Origin header are refused, so a key never ends up in page source.
curl https://api.portail.cc/api/v1/me \
-H "Authorization: Bearer $PORTAIL_API_KEY"Permissions
Each key carries only the permissions you picked when you made it. Need a different set? Make another key.
| memory:read | Read memory. Search what Portail remembers about you. |
| connectors:read | Read connected apps. List events, fetch email, search pages. Nothing changes. |
| connectors:write | Act in connected apps. Send email, create events, publish posts. Real actions on your accounts. |
Endpoints
| Method | Path | Permission | What it does |
|---|---|---|---|
| GET | /me | Any | Which key this is and what it can do. |
| POST | /memory/query | memory:read | Search your saved memory. Body: query (1 to 500 characters), limit (1 to 25, default 10), include_active (default true). |
| GET | /connectors | connectors:read | Every connector, whether it's connected, and each tool with its effect and arguments. |
| POST | /connectors/{connector}/{tool} | connectors:read | connectors:write | Run one connector tool. Body: arguments, holding only the names that tool lists. Read tools need connectors:read. Write tools need connectors:write and an Idempotency-Key header. |
Examples
curl -X POST https://api.portail.cc/api/v1/memory/query \
-H "Authorization: Bearer $PORTAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "preferred stack", "limit": 5}'curl -X POST https://api.portail.cc/api/v1/connectors/google_calendar/list_events \
-H "Authorization: Bearer $PORTAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"arguments": {"start_period": "2026-10-05T00:00:00Z", "end_period": "2026-10-12T00:00:00Z"}}'curl -X POST https://api.portail.cc/api/v1/connectors/gmail/send_email \
-H "Authorization: Bearer $PORTAIL_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: invoice-1042-reminder" \
-d '{"arguments": {"to": "client@example.com", "subject": "Invoice 1042", "body": "A friendly nudge."}}'Writes need an Idempotency-Key
Write tools send real email, create real events and publish real posts, so every write carries an Idempotency-Key header you choose (8 to 128 characters, like an order id). Retry with the same key and the same body and you get the first response back, marked Idempotency-Replayed, instead of a second email. Keys are remembered for 24 hours per API key. If a write fails, the key is released and a retry runs it again.
Limits
60 requests per minute per key, up to 5 active keys per account. Each account also gets 2,000 connector reads and 100 connector writes a day, shared across all its keys, reset at midnight UTC. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Go over any limit and you get 429 with Retry-After.
Errors
Every error is JSON with a stable code, a readable message and the request id. Quote the request id if you write to support.
{
"error": {
"code": "insufficient_scope",
"message": "This key does not have the connectors:write scope.",
"request_id": "5f0c2a1e-..."
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | idempotency_key_required | A write was sent without an Idempotency-Key. |
| 401 | missing_key | No key in the Authorization header. |
| 401 | invalid_key | The key is wrong or was revoked. |
| 403 | browser_request | The request came from a browser. |
| 403 | account_disabled | The account that owns the key was deleted or disabled. |
| 403 | plan_required | The key's owner isn't on a paid plan. |
| 403 | insufficient_scope | The key lacks the permission this call needs. |
| 409 | connector_not_connected | Connect that app in Portail first. |
| 409 | idempotency_in_progress | The same write is still running. Retry shortly. |
| 422 | idempotency_conflict | That Idempotency-Key was already used for a different request. |
| 429 | rate_limit_exceeded | Slow down. Wait for Retry-After. |
| 429 | daily_limit_exceeded | The account used up today's connector calls. Wait for Retry-After. |
| 502 | connector_error | The connected app refused or failed the action. |