Agents

Update an agent

Partially updates an agent using JSON Merge Patch semantics (RFC 7396):

  • Omitted field — the stored value is left unchanged.
  • Explicit null — clears the value. Only description accepts null (it is never null, so an explicit null maps to "").
  • Any other value — replaces the stored value.

name has no meaningful "unset" state: an explicit null falls back to the stored value, same as omitting it — it can never be blanked.

slug changes only when you send it: renaming an agent never changes its slug on its own, and an explicit null is treated as omitted. A sent slug is trimmed and lowercased, must match the create path's rules, and must be unique in the project (409 names the colliding slug). Changing it has effects outside this agent: saved links, Terraform references and trace sources (service.name) that name the old slug stop matching this agent, unless a source also equals the agent's name (case-insensitive), which still matches.

patch/api/v1/agents/{id}

Request

  • Base URL: https://app.lastping.dev
  • URL: https://app.lastping.dev/api/v1/agents/{id}
  • Auth: API key in header X-Api-Key

Request body

namestring

Human-readable agent name. Surrounding whitespace is trimmed, as on create. A new name must be at most 200 characters (not bytes) and free of control and invisible characters (400 INVALID_NAME); sending the stored name unchanged is always accepted. Bytes that are not valid UTF-8 are replaced with U+FFFD when the request is decoded, and accepted.

descriptionstring nullable

Free-text description. Explicit null clears it to ""; omitting the field leaves the stored value unchanged.

slugstring nullable

New slug for the agent. Omitted or null keeps the stored slug, even when name changes. Trimmed and lowercased, then it must match ^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$ and not be UUID-shaped (400 otherwise), and it must be unique in the project (409 names the colliding slug). Saved links, Terraform references and trace sources (service.name) that name the old slug stop matching this agent, unless a source also equals the agent's name (case-insensitive), which still matches. The change reaches back: runs on monitors this agent does not own are matched to an agent when they are read, so past traced runs from the old slug's source lose this agent and drop out of ?agent=, while the dependency totals counted when those traces arrived stay with it. A slug also outranks another agent's name match or adopted source: a new slug equal to a source another agent receives that way takes that source's traces, past runs included.

Example request

{
  "name": "Nightly ETL bot",
  "description": "Runs the nightly ETL pipeline and owns its monitors.",
  "slug": "nightly-etl-bot"
}

Response

Updated agent.

idstring uuid required

Unique agent identifier.

slugstring required

Stable project-scoped identifier, derived from name at creation and immutable thereafter.

namestring required

Human-readable name.

descriptionstring required

Free-text description (empty string if not set).

status'down' | 'blocked' | 'late' | 'running' | 'up' | 'pending' | 'idle' required

Rolled up live from the monitors this agent owns, worst status first: down > blocked > late > running > up > pending > idle. Paused and in-maintenance monitors never contribute: muting a monitor must neither hide a broken agent nor drag a healthy one down.

  • down — at least one owned, active monitor is down.
  • blocked — no active monitor is down, but at least one owned monitor has a run that is blocked on a human right now. This is an alert-class state, not merely informational: it is excluded from the informational alert rate limit precisely so it cannot be starved by high-volume traffic.
  • late — no active monitor is down or blocked, but at least one is late.
  • running — no active monitor is down, blocked or late, but at least one owned monitor has a run currently in flight.
  • up — no active monitor is down, blocked, late or running, and at least one is up.
  • pending — the agent owns at least one monitor, but none of its active monitors has ever reported (only ever seen new). This usually means the wiring is wrong — the agent registered but never pinged.
  • idle — the agent owns no monitors, or every monitor it owns is paused or in maintenance. There is nothing to judge yet.
monitor_countinteger required

Number of monitors this agent owns. 0 for an agent with no monitors.

last_seenstring date-time nullable

RFC 3339 timestamp: the latest ping or traced span across ALL monitors this agent owns, including paused and in-maintenance ones — this answers "when did I last hear from this agent at all", not "is it healthy". A span counts from the end time it reports, recorded at most once a minute per monitor. Null or omitted for an agent that has never received a ping or a span on any of its monitors.

created_atstring date-time required

RFC 3339 UTC timestamp when the agent was created.

Example response

{
  "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
  "slug": "nightly-etl-bot",
  "name": "Nightly ETL bot",
  "description": "Runs the nightly ETL pipeline and owns its monitors.",
  "status": "up",
  "monitor_count": 3,
  "last_seen": "2026-07-10T03:00:05Z",
  "spend_24h": {
    "cost_usd": "0.006600",
    "cost_source": "estimated",
    "tokens_in": 150,
    "tokens_out": 50,
    "runs": 1
  },
  "runs_7d": [
    {
      "day": "2026-09-14",
      "runs": 12
    }
  ],
  "usage_24h": {
    "day": "2026-09-20",
    "model": "claude-sonnet-4-5",
    "provider": "anthropic",
    "tokens_in": 182340,
    "tokens_out": 20411,
    "tokens_cache_read": 95012,
    "tokens_cache_write": 4100,
    "cost_usd": "0.853221",
    "cost_source": "estimated",
    "origin": "traces"
  },
  "top_dependencies": [
    {
      "kind": "database",
      "name": "postgresql",
      "direction": "out",
      "calls": 1480,
      "errors": 12,
      "error_rate": 0.0081,
      "p50_ms": 10,
      "p95_ms": 25,
      "series": [
        {
          "day": "2026-09-20",
          "calls": 210,
          "errors": 2
        }
      ]
    }
  ],
  "created_at": "2026-07-01T12:00:00Z"
}

Changes

No recorded changes to this operation across all 2 revisions of this API.