SDK

Webhooks

Get notified when a customer's agent changes state, instead of polling. Subscribe a URL, and Maritime POSTs a signed JSON body on every lifecycle event.

Events

Each delivery carries the agent's external_id, so you route it to your own customer without a lookup.

EventFires when
agent.deployedthe agent finished deploying and is ready
agent.errorthe agent entered an error state
agent.sleepingthe agent auto-slept after going idle
agent.wokena sleeping agent was woken
agent.restartedthe agent was restarted
agent.stoppedthe agent was stopped

Subscribe

Create a subscription once. The signing secret is returned once. Store it to verify deliveries.

const hook = await maritime.webhooks.create({
  url: 'https://your-app.com/maritime/webhook',
  events: ['agent.error', 'agent.deployed'],   // omit for all events
})
// hook.secret is shown once. Store it to verify signatures.
await maritime.webhooks.test(hook.id)          // deliver a synthetic ping

Verify the signature

Every delivery is signed. Verify the X-Maritime-Signature header (an HMAC-SHA256 of the raw body with your secret) before trusting the payload. Fail closed if the secret is unset. Never verify against an empty key.

your webhook handler
import crypto from 'node:crypto'

const SECRET = process.env.MARITIME_WEBHOOK_SECRET
if (!SECRET) throw new Error('MARITIME_WEBHOOK_SECRET is required')

export async function POST(req: Request) {
  const raw = await req.text()  // exact bytes: the signature is over these
  const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(raw).digest('hex')
  if (req.headers.get('x-maritime-signature') !== expected) {
    return new Response('bad signature', { status: 401 })
  }
  const event = JSON.parse(raw)
  // { event: 'agent.error', agent_id, external_id, timestamp, data: {...} }
  console.log(event.event, 'for your customer', event.external_id)
  return new Response('ok')
}
Deliveries are best-effort and carry X-Maritime-Event and X-Maritime-Delivery headers. An endpoint that fails repeatedly is auto-disabled; re-enable it (or update its events) via maritime.webhooks.list() and the dashboard.

Runnable receivers

Full webhook receivers (Express + Flask) that verify the signature are in the examples.