Skip to content

Developer docs

Automations

Node graphs that run on a schedule — pull metrics, check a condition, build a report, run the AI marketer, call a webhook, send an email. Create them from code or let your assistant build them over MCP.

An automation is a small graph: one trigger, then data, logic, action and notify nodes wired together. The worker runs it on its schedule (or when you call /run), node by node, and keeps a run log with every node's output. Built-in examples: a weekly report by email, an ad-spend spike alert, a daily AI marketer check-up.

text
trigger.schedule ──▶ data.metrics ──▶ logic.condition ──true──▶ notify.email
   (weekday 09:00)     (yesterday)      (spend_change > 30)

Automations are different from apps (linear media pipelines) and from report schedules (one report, no logic).

Endpoints

All routes take an API key or an OAuth token; any workspace member may create, edit and run. Deleting needs the creator or an admin.

EndpointBody / query → result
GET /v1/automations?workspaceId=AutomationDto[] — with issues[], nextRunAt, lastStatus, creditsThisMonth
POST /v1/automations{ workspaceId, name, graph, description?, settings?, enabled? } → AutomationDto. Saved even when incomplete; issues[] says what is missing
GET / PATCH / DELETE /v1/automations/{id}PATCH takes any subset of the create body. enabled: true is refused (400 VALIDATION_ERROR, details.issues) while issues remain
POST /v1/automations/{id}/runRun now → AutomationRunDto (QUEUED). 409 CONFLICT while a run is in flight; 429 past maxRunsPerDay
GET /v1/automations/{id}/runs?cursor=&limit=paged AutomationRunDto (newest first)
GET /v1/automations/runs/{runId}One run with steps[] — status, output and error per node

Graph

json
{
  "nodes": [
    { "id": "trigger", "type": "trigger.schedule", "x": 0,   "y": 80, "config": { "cron": "weekday_09", "timezone": "Asia/Seoul" } },
    { "id": "metrics", "type": "data.metrics",     "x": 280, "y": 80, "config": { "productId": null, "days": 1 } },
    { "id": "check",   "type": "logic.condition",  "x": 560, "y": 80, "config": { "field": "metrics.spend_change", "op": "gt", "value": 30 } },
    { "id": "email",   "type": "notify.email",     "x": 860, "y": 0,  "config": { "to": ["me@company.com"], "subject": "[Poremu] Spend up {{metrics.spend_change}}%", "body": "{{metrics.periodEnd}}: ₩{{metrics.spend}} (CPA ₩{{metrics.cpa}}, ROAS {{metrics.roas}})" } }
  ],
  "edges": [
    { "id": "e1", "from": "trigger", "to": "metrics" },
    { "id": "e2", "from": "metrics", "to": "check" },
    { "id": "e3", "from": "check",   "to": "email", "port": "true" }
  ]
}

Rules (checked by the server, reported in issues[]): exactly one trigger and nothing points into it; no cycles; every node reachable from the trigger; per-type config valid; at most 30 nodes and 60 edges; schedules at least 60 minutes apart; a valid IANA timezone; email recipients are workspace members only; webhook and product ids belong to the workspace. x / y are only for the canvas.

Nodes

NodeConfigOutput ({{key.field}})Credits
trigger.schedulecron — 5 fields or a preset: hourly, daily_09, weekday_09, weekly_mon_09, monthly_1_09; timezone—0
trigger.manual— (run with /run)—0
data.metricsproductId?, days (period ending yesterday)metrics.<metric>, metrics.<metric>_change (% vs the previous period), metrics.periodStart / periodEnd0
logic.conditionfield (context path), op (gt gte lt lte eq neq contains exists), valuecondition.result, condition.actual; outgoing edges use port: "true" / "false"0
action.reportproductId?, daysreport.id / title / url / shareUrl / summary5
action.agentgoal (templated), productId?, model?agent.runId / text / approvals / proposals / creditsthe run's charge (LLM + platform)
action.webhookwebhookIds[] (workspace webhook endpoints), messagewebhook.delivered / failed — sent as event automation.notify, Slack-shaped for Slack endpoints0
notify.emailto[], subject, body (templated, markdown)email.sent / failed0

Metrics available: spend impressions clicks ctr cpc conversions cpa revenue roas installs signups purchases leads visits followers. Always available in templates: {{automation.name}}, {{automation.url}}, {{run.date}}, {{nodes.<id>.<field>}}.

Settings

FieldDefaultMeaning
maxRunsPerDay48Scheduled + manual runs per rolling 24 h (max 48)
maxCreditsPerRun5,000A node that would exceed this is not run; the run fails with LIMIT_REACHED
maxCreditsPerMonth100,000Same, per calendar month (Asia/Seoul) for this automation
notifyOnFailure[][]Member emails told when a run fails
pauseAfterFailures3Disable after this many failures in a row (0 = never)

Scheduled runs charge the creator; manual runs charge the caller. Emails are capped at 200 per workspace per day across automations and report schedules.

Runs

text
schedule due, or POST /run  →  AutomationRun QUEUED (graph snapshot)
worker (5 s)                →  PROCESSING: nodes in topological order
                               a node runs iff an incoming edge comes from a SUCCEEDED node on the matching port; others are SKIPPED
                               node error → that step FAILED, the rest SKIPPED, run FAILED
end                         →  SUCCEEDED | FAILED (+ failure email, failureStreak, auto-pause)
PROCESSING for 20 min       →  FAILED TIMEOUT

steps[] on a run: { nodeId, type, status: PENDING | RUNNING | SUCCEEDED | FAILED | SKIPPED, output?, error?, credits, startedAt, completedAt }. Realtime clients receive automation_run.updated on every step; outputs there are trimmed to 200 characters — fetch the run when it is terminal.

Example: create and run

bash
curl https://api.poremu.ai/v1/automations \
  -H "Authorization: Bearer $POREMU_API_KEY" -H "Content-Type: application/json" \
  -d @spike-alert.json      # { "workspaceId": "my-workspace", "name": "Spend spike", "graph": { … }, "enabled": true }

curl -X POST https://api.poremu.ai/v1/automations/AUTOMATION_ID/run \
  -H "Authorization: Bearer $POREMU_API_KEY"

curl "https://api.poremu.ai/v1/automations/runs/RUN_ID" \
  -H "Authorization: Bearer $POREMU_API_KEY"

Over MCP

Your assistant can build these for you: automation_catalog returns the node specs, operators, presets, limits and the three templates; create_automation takes a graph (positions and edge ids optional) or a templateId — weekly-report-email, spend-spike-alert, daily-ai-checkup — with {{me}} recipients replaced by your address; update_automation turns it on; run_automation and list_automation_runs show results.

"Create an automation: every Monday 09:00 build last week's report for Lumo and email it to me and jay@lumo.app. Turn it on."