Logging notes from your AI — POST /v1/notes
POST /v1/notes appends a note to an account, opportunity, or contact. It's the most useful single endpoint for AI assistants — "log this call to the Acme deal" is the #1 thing an AI is asked to do mid-conversation.
Request:
POST /v1/notes
Authorization: Bearer turtini_...
Content-Type: application/json
{
"entity": "opportunity",
"entityId": "opp_abc123",
"text": "Left voicemail re: renewal — try again Thursday."
}
Required scope: notes:write
Body:
• entity (required) — one of: account, opportunity, contact
• entityId (required) — the parent record ID. Must belong to the caller's org.
• text (required) — plain text, max 10,000 chars
Response (201 Created):
{
"id": "note_xyz",
"text": "Left voicemail re: renewal...",
"authorId": "apiKey:abc123",
"authorName": "API: Cursor on jane's MacBook",
"createdAt": "2026-05-05T18:24:00.000Z",
"orgId": "...",
"via": "public_api",
"path": "opportunities/opp_abc123/notes/note_xyz",
"parent": { "entity": "opportunity", "id": "opp_abc123" }
}
Cross-org safety:
If the parent record doesn't exist OR belongs to another tenant, the response is 404 (not 403) — so an attacker can't probe-by-existence. The error message doesn't distinguish.
Idempotency:
Pass an Idempotency-Key header (UUID-shaped). Repeated requests with the same key for 24 hours return the cached response — useful when an AI agent retries a failed write.
Audit:
Each note is stamped with via='public_api' and authorId='apiKey:<keyId>'. The note appears in the record's normal Notes panel attributed to the key's friendly name. Revoking the key disables further writes; existing notes remain.
In MCP / SDK:
• MCP tool: note_create({ entity, entityId, text })
• SDK: turtini.notes.create({ entity, entityId, text })