log_action
Record something you (or the user) just did or observed on a growth item: what happened (one sentence is enough), the new stage only if you know it…
Record something you (or the user) just did or observed on a growth item: what happened (one sentence is enough), the new stage only if you know it changed, when to follow up, and any outcome. Pass an opportunity id or a URL (an unknown URL is tracked automatically); with neither, only the action is recorded. The server never infers a stage from the action. Do not put private message text or personal data in summaries. Use idempotency_key to make retries safe.
| Field | Value |
|---|---|
| Pack | Core (core) |
| Estimated cost per call | $0 |
| Monthly pack limit | none |
| Project | resolved: explicit project → header → credential default → workspace default |
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
project | no | string | Project slug or id. Omit to use the credential or workspace default. |
opportunity_id | no | string | The opportunity this is about (id from track or get_briefing). Use this or url, not both. |
url | no | string (≤ 2000 chars) | Or the post/profile URL it is about; an unknown URL is tracked automatically. |
title | no | string (≤ 200 chars) | Title for a newly tracked URL. |
action | yes | object | What was done or observed. |
action.kind | no | string (≤ 50 chars) | What kind of action, e.g. 'comment', 'dm', 'post', 'email'. Default 'action'. |
action.summary | yes | string | One sentence on what happened, e.g. 'Replied with a comparison table'. No private message text. |
action.channel | no | string (≤ 100 chars) | Where, e.g. 'reddit', 'x', 'xiaohongshu'. |
action.url | no | string (≤ 2000 chars) | Link to what you posted, e.g. your comment URL. |
action.occurred_at | no | ISO datetime | When it happened (ISO time). Default: now. |
stage | no | "discovered" | "contacted" | "replied" | "willing_to_talk" | "converted" | "dropped" | New stage, only if you know it changed: discovered, contacted, replied, willing_to_talk, converted or dropped. |
next_followup | no | ISO datetime | {in_days} | {at} | null | When to follow up: {"in_days": 3}, {"at": ISO time}, or an ISO time. null clears it. Default: a stage-based suggestion. |
experiment_id | no | string | Attach this action to an experiment (id from track). |
link_code | no | string (≤ 32 chars) | Code of a short link used in this action (from track type=link), for click attribution. |
outcome | no | object | A result of this action, if there is one. |
outcome.type | yes | string (≤ 60 chars) | What was achieved, e.g. 'signup', 'reply', 'call_booked'. |
outcome.value | no | number | Amount, e.g. 1 or 49.9. |
outcome.unit | no | string (≤ 20 chars) | Unit of value, e.g. 'usd', 'count'. |
outcome.evidence | no | string | How you know, e.g. 'Reply in thread from the author'. |
note | no | string | Extra context, one or two sentences. |
idempotency_key | no | string (≤ 100 chars) | Any unique string; repeating the call with the same key does not record it twice. |
Example call
{
"project": "acme-crm",
"url": "https://www.reddit.com/r/SaaS/comments/1abc23/looking_for_a_lightweight_crm",
"action": {
"kind": "comment",
"summary": "Replied with a comparison table",
"channel": "reddit"
},
"stage": "contacted",
"experiment_id": "exp_7Hn2LpWc0",
"idempotency_key": "2026-10-16-comment-1abc23"
}REST: POST https://service.opennomos.com/v1/tools/log_action with that JSON as the body. MCP: tools/call with name: "log_action" and that JSON as arguments.
Example result
Values are illustrative; the shape comes from the service code.
{
"project": {
"id": "prj_k3Vd9aQx2",
"slug": "acme-crm"
},
"action_id": "act_Lw03pKd8",
"opportunity": {
"id": "opp_Qm4x9TnB1",
"stage": "contacted",
"next_followup_at": "2026-10-19T09:30:00.000Z",
"events": 3
},
"experiment_progress": {
"id": "exp_7Hn2LpWc0",
"metric": "willing_to_talk",
"current": 1,
"target": 3,
"deadline_at": "2026-10-30T09:00:00.000Z"
},
"hints": []
}Notes
- The write-back half of the loop. OpenNomos never posts, replies or messages anyone: you (or the user) do that elsewhere, then record it here.
- Pass
opportunity_idorurl(an unknown URL is tracked automatically). With neither, only the action is recorded. - Defaults: the server never infers a stage. If
stageis omitted the stage stays. Ifnext_followupis omitted the follow-up time stays unless the stage actually changed, in which case it is set from the new stage:contacted+3 days,replied+2,willing_to_talk+2,convertedanddroppedclear it.next_followup: nullclears it. Details in log_action defaults. outcomerecords a result (type, optionalvalue,unit,evidence). It is counted as attributed (direct) only when it is tied to an opportunity or a short link; otherwise it isunknown. See Attribution.idempotency_keymakes retries safe: repeating a call with the same key replays the first result (withduplicate: true) instead of recording twice.experiment_progressappears when the action is attached to an experiment.hintscan contain a one-line warning, for example whenoutcome.typeiswilling_to_talkbut the stage was not changed.- Do not put private message text or personal data in
summaryornote.
Errors
Rejected calls (bad input, unknown ids, rate limits) return message and code; over MCP the result has isError: true. See Errors.