Event-Driven Orbs
Webhooks
An Amp plugin can create a public HTTP endpoint that stores events and wakes its orb. Use a webhook when an external service such as GitHub needs to start work in an orb. Unlike a portal, a webhook does not expose a server running inside the orb.
Webhooks work only in plugins running in Amp-managed orbs. Register the handler from the plugin’s entry point with a short, stable key:
const { url } = await amp.createWebhook({
key: 'github-events',
headers: ['x-hub-signature-256'],
handler: async (event, ctx) => {
await verifyAndApply(event.id, event.body, event.headers['x-hub-signature-256'], ctx.signal)
},
}) The returned url accepts POST requests. Configure that URL in the external service. Ask Amp to
create and load the plugin when you do not need to write it yourself. Run amp plugins show-docs inside the orb to read the Plugin API installed there.
Example
You can ask Amp in an orb thread to write, load, and wire up the webhook plugin for you:
Amp writes the plugin into .amp/plugins/, loads it, and replies with the webhook URL to paste
into the external service.
Delivery Guarantees
For threads in a project, the registration belongs to the user, project, plugin, and key. A checked-in plugin therefore gets the same URL when it loads in another thread in that project. The thread that first registered the webhook remains its owning thread and handles its events. Loading the plugin in another thread still returns that URL when the owning thread is archived, but does not transfer ownership or resume delivery. For threads without a project, each thread gets a separate registration.
Registering the same key again keeps the same URL across plugin reloads and orb restarts. An incoming request is stored before Amp returns HTTP 202, then Amp wakes the owning orb and calls the handler. HTTP 202 means that Amp queued the event. It does not mean that the handler finished.
Delivery is at least once. Store event.id with the action that the handler performs so a retry
cannot apply the same action twice. The handler has 30 seconds to finish. Pass ctx.signal to
cancellable network calls and throw when a temporary failure should be retried. Keep longer work
in a durable queue or start another thread.
A thrown handler defers only that event. Amp retries it after 5 seconds and doubles the wait on each rejection, up to 5 minutes, while later events keep being delivered. Events are therefore not delivered in strict order. An event that the handler keeps rejecting for 24 hours is dropped and logged in the orb’s Amp log. Do not throw to wait for an unrelated condition such as another thread finishing; store the event and return instead.
Rate Limits
Each endpoint accepts a burst of 10 new events and refills at 10 events per minute. Amp returns
HTTP 429 when the endpoint exceeds that rate or has 100 events waiting. Rate limit responses
include Retry-After. A request body can be at most 1 MB. Send a stable Idempotency-Key header
when the sender retries a request. A retry for an event that is still waiting does not use more
rate capacity.
Security
Treat the webhook URL as a password. Anyone with it can submit events without signing in to Amp. Do not commit it, put it in a thread message, or write it to normal logs. If you save it in the orb, use a gitignored file that only the owner can read. Archiving the owning thread pauses the orb and makes the URL return HTTP 404.
Amp does not verify signatures from the external service. Add each signature or authorization
header to headers, store the matching secret in project settings,
and verify the signature before acting. Amp discards request headers that the plugin did not list.
Validate the body and requested headers as untrusted input, and never use webhook text as agent
instructions without checking it first.
Trigger Settings
Use trigger settings to pause or delete a webhook. Pausing keeps its URL but rejects new events until you resume it. Deleting it revokes the URL and removes its queued events.
If delivery is paused because the owning thread is archived, trigger settings show the reason and link to that thread. Restore the owning thread to allow delivery again. If you also paused the trigger in settings, it stays paused until you resume it there.
Keeping Threads Active
Use these rules for a thread that owns CI, a webhook, or other long-running automation:
- Keep the owning thread unarchived. Archiving pauses its orb and webhook delivery.
- Remove workspace or personal guidance that tells Amp to archive the thread when work finishes.
- For CLI execute mode, pass
--no-archive-after-execute. For SDK execute mode, setnoArchiveAfterExecutein TypeScript orno_archive_after_executein Python. - Publish a plugin to the workspace when every member must install it. Workspace publication does not transfer an existing webhook to a different owner or thread.
Testing
You can test an endpoint without putting its URL in shell history:
read -rsp 'Webhook URL: ' AMP_WEBHOOK_URL && echo
curl --fail-with-body \
-X POST \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: test-event-1' \
--data '{"action":"test"}' \
"$AMP_WEBHOOK_URL"
unset AMP_WEBHOOK_URL For scheduled and recurring work, see Automations.