Developers

The Presend API

The same gate the extension runs, callable from your own code. Send a draft, get back findings with the offending text and a suggested fix.

Base URL and authentication

Everything lives under https://api.getpresend.com over HTTPS. Requests carry a bearer token tied to your account:

Authorization: Bearer <your-token>

A token scopes the check to you, which is what makes your custom rules and your voice profile apply. Without one the local rules still run, but the answer is weaker than you think you asked for.

Create one in the dashboard under Settings, API keys. The value is shown once and never again, so store it where you keep your other secrets. Revoking takes effect immediately.

Keys look like presend_sk_…. That prefix is deliberate: it is what lets secret scanners spot one committed to a repository by accident, and what lets Presend itself flag one in a draft.

Unlike a browser session, a key does not expire. A script or an agent set up once keeps working.

Check a draft

POST /api/check/score runs the full gate: local rules, your custom rules, voice and slop scoring.

curl -X POST https://api.getpresend.com/api/check/score \
  -H "Authorization: Bearer $PRESEND_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Re: pricing",
    "body": "Hi — happy to do 40% off, key is sk-ant-abc123.",
    "platform": "gmail",
    "recipients": [{ "email": "buyer@example.com" }],
    "depth": "send"
  }'
bodystring, requiredThe draft text.
subjectstringEmail subject, where the surface has one.
platformstringgmail, outlook, slack, linkedin, twitter or generic. Decides which rules apply and how loud they are.
recipientsarrayObjects with an email. Needed for the external-recipient check.
hasAttachmentbooleanWhether a file is actually attached.
mentionsAttachmentbooleanWhether the text claims one is.
depthstringlive or send. See below; defaults to live.

The response carries the findings and two scores:

{
  "findings": [
    {
      "id": "secret-anthropic-key",
      "level": "risk",
      "title": "Anthropic API key in the message",
      "detail": "This looks like a live credential.",
      "original": "sk-ant-abc123",
      "suggestion": "Remove it and rotate the key.",
      "occurrence": 1
    }
  ],
  "voiceScore": 71,
  "slopScore": 12,
  "aiLimited": false,
  "deepCheckRan": true
}

level is risk, warn or info. Treat risk as a stop. original is the exact text that tripped the rule, so you can highlight it.

aiLimited comes back true when the free daily limit was reached and AI scoring was skipped. The local rules still ran, so the answer is real, just shallower.

Rules only, at no AI cost

POST /api/check/rules takes the same body and runs only the deterministic checks: secrets, personal data, links, recipients, attachments. No model call, no usage counted, fast enough to run on every keystroke.

Rewrite

POST /api/check/rewrite returns the draft rewritten, keeping your voice rather than flattening it into house style.

Live and send depth

live is what the extension runs while someone types: local rules, pattern rules, plain AI rules. It never calls out to your connected tools, because a keystroke cannot wait on a Jira round trip.

send is the full gate, including rules that consult your own systems. Use it once, at the moment you are about to send.

Limits and errors

Free accounts get 25 AI-backed checks a day. The rules-only endpoint is unlimited. Pro removes the daily cap.

A 401 means the token is missing, expired or wrong. A 4xx carries a message field written for a human. Rate limiting answers 429 with the seconds to wait.

Calling it from an agent instead

If the caller is an AI agent rather than your own code, use the MCP server. It exposes the same checks as tools a model can call directly.