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:

Create a plugin that registers a webhook with the key `github-events` and captures the `x-hub-signature-256` header. When GitHub sends a push event for the default branch, pull the latest changes, run the test suite, and reply in this thread with the result. Verify the signature with a secret from a gitignored file before acting, and dedupe on the event ID. Load the plugin and give me the webhook URL and setup steps for GitHub.

Amp writes the plugin into .amp/plugins/, loads it, and replies with the webhook URL to paste into the external service.

Delivery Guarantees

The registration belongs to the orb thread, plugin, and key. 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 a paused 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.

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.

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.