Valta Docs

Webhooks

Available now. Webhooks are available from the dashboard (Startup plan and up) and via the SDK/API described below (valta.webhooks.*, /api/v1/webhooks).

Instead of polling GET /api/v1/agents/:id/runs, your server receives a signed HTTP POST each time a Valta event fires.

Events

EventFires when
agent.run.completedAn agent run finishes successfully
agent.run.failedAn agent run fails
agent.frozenAn agent is frozen
agent.approval_requiredAn agent run is paused waiting for approval
wallet.depositFunds are deposited into an agent wallet
wallet.low_balanceA wallet drops below the configured threshold
policy.violationAn agent attempts an action that violates policy
audit.injection_detectedA prompt injection attempt is blocked

Register a webhook

ts
await valta.webhooks.create({
  url: 'https://your-server.com/valta-events',
  events: ['agent.frozen', 'wallet.deposit', 'policy.violation'],
  secret: process.env.VALTA_WEBHOOK_SECRET,
})

Verify and handle on your server

ts
app.post('/valta-events', (req, res) => {
  const sig = req.headers['x-valta-signature']
  const valid = valta.webhooks.verify(req.body, sig, process.env.VALTA_WEBHOOK_SECRET)
  if (!valid) return res.status(400).end()

  const { type, data } = req.body
  if (type === 'agent.frozen') {
    // Send Slack alert, page on-call, etc.
  }
  res.status(200).send('OK')
})

Reliability

  • HMAC-SHA256 signature on every request (x-valta-signature: sha256=...) — verify before processing.
  • Retried with real backoff. If the first attempt fails (non-2xx, timeout, or your endpoint is unreachable), Valta retries twice more shortly after (a few seconds, then again a few seconds later) without holding up whatever action triggered the event. A delivery still failing after that is retried again the next time any webhook event fires on your account, up to a bounded number of total attempts, before it's marked failed.
  • No idempotency key on the event payload yet. Each event carries event, its own fields, and timestamp — no dedup key. Retries only resend on a genuine failure (no response received as successful), but if your endpoint did process a delivery and only the response was lost, a retry can still arrive as a real duplicate. Design your handler to be safe to run twice until a dedup key ships.
  • Delivery history is real and queryable: GET /api/user/webhooks/:webhookId/deliveries returns every attempt — event type, status, HTTP response code, error, and exactly when each attempt happened. This is the "did we actually send this, and when" answer for reconciliation.

Not yet built: exponential backoff tuned per-endpoint, and a dashboard view of delivery history (the data exists via the API above; no UI on top of it yet).