Docs / Wake your agent

Wake your agent

Maplith wakes your agent when something in your business moves: a signed call to your endpoint, how to verify it, the limits you set and how to start your own Claude agent.

Maplith wakes your agent when something in your business moves. Instead of your agent asking Maplith every few minutes whether there is work, Maplith calls an address of yours the moment a signal your agent cares about is raised, or a person decides one of its requests.

On as soon as you set your agent up. Wake-ups start for your workspace the moment you set up its first wake endpoint, in Agents & access › Connections or by an agent whose key may act on its own. They need your organisation to have accepted the current Data Processing Agreement, under which Maplith's processing description covers notices to an endpoint you set up; until it has, nothing is sent, and setting up an endpoint tells you why. An admin can turn wake-ups off for the workspace in Agents & access › Connections › Wake-ups; then nothing is sent and no endpoint can be added until an admin turns them back on, and Maplith does not switch them on over that choice. If Maplith switches a workspace's wake-ups off, for misuse or an incident, setting up an endpoint does not turn them on again until Maplith does. Your agent can always find its work with list_signals: polling keeps working, and stays the fallback.

How a wake-up works

  1. A signal is raised that your agent's key may see and the wake-up's filter asks for — or a person approves or denies one of the key's pending requests.
  2. Maplith sends one signed POST to your endpoint: your agent runtime, a scheduler, or a webhook that starts your agent.
  3. Your agent starts and calls get_task_context (or list_signals) with its own key, so it is shown exactly what that key may see, as on any other call.

A wake-up is a nudge, not the work. It names signal ids and nothing else: no title, no description, no object or field name, no figures and never a row. What the signal is about is read through Maplith, with the key's scope and your action policy applied, so a wake-up that reached the wrong address would tell its reader nothing.

Set one up

A wake-up belongs to one agent key; a key can have up to three.

  • In the app. An admin who sees the whole map opens Agents & access › Connections › Wake-ups, chooses the key and adds a wake-up: the address to call (https, port 443), which kinds of signal, objects or domains, the least severe signal that counts, and whether a person's decision on one of the key's requests wakes it too. Choosing nothing in a list means all of it, within what the key sees. Send a test checks your endpoint receives and verifies a wake-up.
  • By the agent itself. A key with the policy "can act" (autonomous) manages its own wake-ups over MCP: set_wake_subscription (which also sends a signed test wake-up to a new endpoint, a re-keyed one, or on request) and remove_wake_subscription. Every key reads its own wake-ups in get_map_overview's your_key.wake_ups; an admin sets them up for a key that cannot, and sends a test from Agents & access › Connections.

The filter only ever narrows what the key already sees. An object or domain outside the key's scope is refused when the wake-up is saved, and if the key's scope is narrowed later, a wake-up names only the signals the key may see when it is sent.

The signing secret is shown once, when the wake-up is made and when you replace it. Store it in your runtime's secret store at once: Maplith cannot show it again. After a replacement the old secret keeps signing beside the new one for 24 hours, so your endpoint can switch over without missing a wake-up.

What your endpoint receives

HeaderValue
X-Maplith-Signaturet=<unix seconds>,v1=<hex> — during the 24 hours after a secret is replaced, two v1 values
X-Maplith-Deliverywd_<id>, the same as delivery_id in the body; it stays the same when a wake-up is sent again
Content-Typeapplication/json
{
  "type": "signals.raised",
  "delivery_id": "wd_6f1c…",
  "workspace_id": "…",
  "subscription_id": "…",
  "sent_at": "2026-10-11T09:20:04Z",
  "signals": [{ "id": "…", "kind": "rule_fired", "severity": "attention", "episode": 3 }],
  "more": 0
}
  • type is signals.raised, approval.decided or test.
  • signals names at most 50; more counts the rest, which your agent reads with list_signals.
  • approval.decided carries "approval": { "request_id", "decision", "signal_id" } instead: decision is approved or denied, and request_id is the approval_id your agent was handed when the request waited for a person. Your agent asks again with the same idempotency key to receive what was decided; nothing that grants anything travels in a wake-up.
  • After a day's cap held wake-ups back, the next one says so: "held_back_since": { "count": 7, "since": "…" }.

Verify every wake-up

The signature is your endpoint's only proof that a call came from Maplith: Maplith holds no token or password for your endpoint, ever. v1 is HMAC-SHA256 over <t>. followed by the raw request body, keyed with your signing secret. Check it over the bytes you received, before any JSON parsing; compare in constant time; refuse a t more than five minutes from your clock; accept when any v1 value matches. Then drop a delivery_id you have already handled.

Node, no dependencies:

import { createHmac, timingSafeEqual } from 'node:crypto';

// header: the X-Maplith-Signature header. rawBody: the request body exactly as
// received (a Buffer or a string), before any JSON parsing. secret: your
// mwk_… signing secret.
export function verifyWake(header, rawBody, secret, nowSeconds = Math.floor(Date.now() / 1000)) {
  const m = /^t=([0-9]{1,12})((?:,v1=[0-9a-f]{64}){1,2})$/.exec(String(header ?? '').trim());
  if (!m || Math.abs(nowSeconds - Number(m[1])) > 300) return false;
  const expected = createHmac('sha256', secret).update(`${m[1]}.`).update(rawBody).digest();
  let ok = false;
  for (const value of m[2].slice(1).split(',')) {
    ok = timingSafeEqual(Buffer.from(value.slice(3), 'hex'), expected) || ok;
  }
  return ok;
}

Python, standard library only:

import hashlib
import hmac
import re
import time

_SIGNATURE = re.compile(r"t=([0-9]{1,12})((?:,v1=[0-9a-f]{64}){1,2})")


def verify_wake(header, raw_body, secret, now_seconds=None):
    """header: the X-Maplith-Signature header. raw_body: the request body as
    bytes, exactly as received, before any JSON parsing. secret: your mwk_...
    signing secret."""
    m = _SIGNATURE.fullmatch((header or "").strip())
    now = int(time.time()) if now_seconds is None else now_seconds
    if not m or abs(now - int(m.group(1))) > 300:
        return False
    expected = hmac.new(secret.encode(), m.group(1).encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    ok = False
    for value in m.group(2)[1:].split(","):
        ok = hmac.compare_digest(value[3:], expected) or ok
    return ok

Both are tested against the code Maplith signs with. It is the same scheme Maplith checks on the reports a live check sends in, so one helper serves both directions.

Bursts and daily limits

A wake-up usually costs you a model run, and Maplith cannot see that cost. The number of wake-ups is what Maplith can count, so that is what you limit.

  • Bursts become one wake-up. The first matching signal opens a window (60 seconds unless you change it, up to 15 minutes; 10 to 15 seconds suits new support conversations). Everything that matches inside it goes out together: a scan that raises forty findings wakes your agent once. A person's decision is sent at once.
  • A daily cap per wake-up (24 unless you change it), and a ceiling for the whole workspace across all of them (100). Signal wake-ups and tests count against both. A person's decision has its own count of the same size per wake-up, so the day's signals never keep a decision from your agent, and it does not count toward the workspace ceiling. The day is the Copenhagen calendar day.
  • At a wake-up's cap nothing more is sent that day, except a decision and a wake-up that names an urgent signal: urgent work is sent past the cap, and counted, until the wake-up has sent four times its cap that day.
  • At the workspace ceiling nothing more is sent that day but decisions, urgent or not: that ceiling is yours, and nothing passes it. Nothing is lost: the signals are still in list_signals, and the next wake-up says how many were held back and since when. Agents & access › Connections and get_map_overview's your_key.wake_ups show where each wake-up stands, such as "9 of 24 wake-ups today".
  • The limits are yours. An admin sets each wake-up's most wake-ups a day and shortest window, and the workspace ceiling. An agent may lower its own cap or wait longer, never more than you allow. While you have paused one of a key's wake-ups or tightened its limits, the agent can neither remove it nor set up another one beside it.

When your endpoint does not answer

  • Your endpoint must answer with a 2xx status within 10 seconds. Maplith does not follow redirects, and keeps only the status of your answer.
  • Retried: a timeout, a network error, 408, 429 and 5xx, after about 30 seconds, 2 minutes, 10 minutes, 30 minutes, 2 hours and 6 hours — seven attempts over about nine hours. Any other status is not retried.
  • A wake-up that is not delivered stays on record with its last status. Three in a row set the wake-up to failing: Maplith stops calling it and raises a link_dead signal with the steps to repair it. An admin presses Resume once the endpoint answers again.
  • 410 Gone ends the wake-up: your endpoint says it is not coming back.
  • Wake-ups can arrive out of order, and the same one can arrive twice. Use delivery_id to drop repeats, and take_signal so two agents do not do the same work.
  • While an admin has paused every agent in the workspace, nothing is sent. What matched in the meantime arrives as one wake-up when they resume.

Start your own Claude agent

A wake-up reaches an address of yours, and something there has to start your agent. Starting it takes a credential of yours, which Maplith never holds, brokers or passes on. So you run a small relay in your own account: it checks the signature and starts your agent with your own token or key. That relay is Maplith Wake, open source (Apache 2.0) with no dependencies, in the wake-relay folder of github.com/Maplith/agents. Once the relay's address is set up as your key's wake endpoint, wake-ups start, on the conditions above: you do not ask Maplith to switch them on. It starts your agent in either of two ways:

  • A Claude Code routine. The relay calls the routine's API trigger with the routine's own token, which is kept in the relay's settings and nowhere else. The text it sends is signal ids, one per line, and nothing else.
  • A Managed Agents session, with your API key, your agent's environment and vault, a cost limit for each session and, if you want one, a daily limit that counts only the sessions the relay started.

What the relay does that a plain address would not:

  • It starts nothing twice. Maplith sends a wake-up again when it hears no answer, and a routine's start has no idempotency key, so the relay remembers each delivery and each signal episode it has started your agent for.
  • It stays under the routine's limit of 30 starts an hour. What would pass the limit waits and goes out in the next start, which can carry up to 50 ids.
  • It tells you when the routine cannot be started, such as after a token was replaced or a routine deleted, in plain words, at an address you choose.

The routine's prompt decides what the ids mean. The template's prompt for support takes each signal, reads the conversation in your helpdesk, leaves an internal note or a draft reply, never sends, records what it did, and then sweeps for any signal it was not given. Give the routine an hourly schedule as well, so that a missed wake-up costs at most an hour, and connect only Maplith and your helpdesk to it.

Start with drafts only. A routine runs its tools without asking and reads text written by people outside your company. Use a helpdesk account that cannot send, set the Maplith key to *Hand over only*, and let a person send every reply.

For a company, use a Team or Enterprise seat for the routine, or the Managed Agents way with API credits. Routines also run on Pro and Max plans, which are plans for individuals.

For those who would rather not run a server, the repository also has a recipe that does the same in n8n or Make.

Where things are in the repository: the README says how to deploy it (one click on Render, or Docker anywhere) and lists every setting; the routine's prompt and its setup guide are in routine/ (PROMPT.md, SETUP.md); the n8n and Make recipe is in recipes/.

What Maplith keeps

The list of past wake-ups — when each was sent, its type, the status your endpoint answered and the attempts — is kept for 30 days and shown in Agents & access › Connections and to the agent's own key. Every change to a wake-up, by a person or an agent, is in your workspace's audit log. The full address is shown only to admins in Agents & access › Connections: an agent is told the scheme and host only, because a webhook address is often a secret in itself.

Related: Signals & rules for what a signal can be, Agent keys & policies for what a key may see and do, and MCP for connecting your agent.

← All docs · Markdown version