SignEnvoy docs
Sign in Start in the sandbox

Events

Polling and webhooks

An envelope changes a handful of times: sent, opened, signed, completed, sealed. A webhook tells you each time, with one request per change. Reading the envelope on a timer mostly returns the same thing, so the API paces it.

Read once to see it

Right after you send, or right after a signer finishes, one read shows the new state at once:

curl -s https://app-staging.signenvoy.com/v1/documents/$DOC -H "Authorization: Bearer $SENV_API_KEY"

That is the right call for a person checking by hand, or for code a webhook has told that something changed.

Get told: webhooks

Add an endpoint under Settings, Developers, Webhooks, or with the API, and subscribe to the events you act on. Most integrations need document.completed (everyone signed) and document.sealed (the signed PDF is ready to download).

curl -s -X POST https://app-staging.signenvoy.com/v1/webhooks \
  -H "Authorization: Bearer $SENV_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://your-app.example.com/webhooks/signenvoy", "events": ["document.completed", "document.sealed"]}'

The response carries the endpoint's signing secret, once. Verify X-SignEnvoy-Signature on every delivery (how), then read the document named in the event. Deliveries that fail are retried for a day (events and retries).

On localhost there is no public URL to deliver to. The CLI forwards the same events to a local handler without a tunnel:

senv webhook tail --forward http://localhost:3000/webhooks/signenvoy --secret YOUR_LOCAL_SECRET

Or read them yourself from the event stream.

If you have to poll

Polling works. These are the rules for GET /v1/documents/{id}:

  • Every 30 seconds. While a document can still change on its own (sent, partially_signed, or completed and not yet sealed), responses carry X-SignEnvoy-Poll-Interval: 30 and a Link to the webhook docs.
  • Send the ETag back. Every read returns an ETag. Send it as If-None-Match and an unchanged document answers 304 Not Modified with no body.
  • Or wait for the change. ?wait=30 holds the request for up to 30 seconds and answers as soon as the document differs from your If-None-Match (or from what it was when the request arrived). At the deadline you get a 304 if nothing changed. A workspace can hold 10 waiting reads at a time.
  • The limit. One API key may read one document 10 times at once, then once every 15 seconds. Past that the answer is 429 polling-too-fast with Retry-After. Other documents and other keys are not affected. A key that keeps reading one document gets an X-SignEnvoy-Notice header suggesting webhooks.
  • Reads can be 5 seconds old. A change made through the API or by a signer is visible to the next read. A change the sealing job makes can take up to 5 seconds to show; the Age header says how old a read is.
ETAG=$(curl -s -D - -o /dev/null https://app-staging.signenvoy.com/v1/documents/$DOC \
  -H "Authorization: Bearer $SENV_API_KEY" | awk 'tolower($1)=="etag:" {print $2}' | tr -d '\r')
curl -s -w '%{http_code}\n' "https://app-staging.signenvoy.com/v1/documents/$DOC?wait=30" \
  -H "Authorization: Bearer $SENV_API_KEY" -H "If-None-Match: $ETAG"