IpInkpacket

Blog

Listen for envelope status webhooks

Subscribe to Inkpacket envelope events — sent, viewed, signed, completed, expired, declined, voided, corrected — verify HMAC-SHA256, and do not treat iframe postMessage as the server record.

Your own systems should hear when an envelope moves without scraping the desk. Set a workspace webhook URL in Settings, or pass webhookUrl on create or send. Inkpacket POSTs a signed JSON body when an envelope is sent, viewed, signed, completed, expired, declined, voided, or corrected. The signing link does not wait on your server. Envelope send still succeeds if that POST fails.

The verify steps and route list live in public API and signed webhooks. The delivery queue is webhook retries explained. Desk help is Docs. This guide is which events to persist, how to prove the POST is ours, and what not to confuse with a parent-tab message.

Which events to listen for

Event order follows the envelope. You will not always see every name. A decline or a void can arrive instead of completed. A multi-signer envelope can fire signed more than once. Completed is the close that means the stamped PDF exists.

  • sent — a signing link was issued. If Resend is missing, the invite was still logged and the desk shows the URL.
  • viewed — someone opened the token (and passed an access code if you set one).
  • signed — that signer submitted required marks. Others on the same envelope may still owe a mark.
  • completed — every signer finished. Download the stamped PDF from the same envelope.
  • expired, declined, voided, corrected — closes and in-place admin on that same envelope id.

If you only persist completed, you will miss a decline that stopped the deal and a void you triggered yourself. Persist the envelope id plus the event name. Treat corrected as an update, not a twin. When to void, correct, or resend is why those verbs stay on one id. Reading an audit trail is the human copy of the same lifecycle.

Prove the POST is ours

Each request includes X-Inkpacket-Event and X-Inkpacket-Signature as t=<unix>,v1=<hex>. Verify with HMAC-SHA256 of timestamp.body using the workspace signing secret. Reject stale timestamps. Rotate the secret in Settings if it leaks. Do not trust the JSON until the hex matches in constant time.

HTTPS is required except on localhost or .test hosts. A missing URL means no delivery is queued. There is no test-send or replay button — send an envelope after saving a URL. Settings shows the last 12 deliveries with status, attempt count, and last error. The first POST is immediate. Failed deliveries retry on the hourly envelope job, up to 5 attempts, then fail.

Not the iframe

Embedded signing posts viewed, signed, and completed to the parent tab. That is UI. The parent can be replayed, ignored, or forged from another script. Your backend should wait for a verified webhook — or read the envelope on GET /api/v1/packets with a Bearer token. Embed signing versus a signing link is when to frame at all.

Workspace URL versus per-packet URL

A workspace URL covers every envelope that does not override it. A per-packet webhookUrl on create or send is for a single envelope — useful when one customer’s app should hear about their envelopes and not yours. Tokens and secrets stay inside the workspace. Staging should not share production’s signing secret or destination.

Owners and admins mint org-scoped Bearer tokens in Settings. Members can send from the desk; they cannot mint tokens. Do not put a token in a browser bundle. API vs desk for ops teams is who should click versus who should POST.

Caps and what is not open yet

A webhook delivery is not an envelope. The send that created the envelope is. Free allows 5 packets a month. Free at 5 packets a month is the cap API send shares with the desk, bulk send, and Web Form fills. Hitting it returns HTTP 402 and code ENVELOPE_LIMIT. Each API token allows 120 requests per minute per token. Over that limit, /api/v1 returns HTTP 429 with a Retry-After header. Inkpacket does not send X-RateLimit headers. Access-code 429 is a PIN lockout, not a send throttle. Starter is 20 envelopes — more than Free — plus 3 published Web Forms. Seat counts are planning numbers.

Billing checkout is not open. Text-message (SMS) is coming soon. Drive missing: Drive not configured. Stripe off: Payments not live. GET /api/v1/health reports the same flags Settings shows. None of those flags pause a signed POST. The envelope still exists if your handler is down.

Make the handler boring

  1. Read the raw body. Verify the signature before you parse for business logic.
  2. Store a delivery key (envelope id + event + timestamp).
  3. Return 2xx quickly. Fan out to your own workers after the acknowledge.
  4. If you must fail, fail closed on signature mismatch — do not 2xx a forged body.

A retry is not a second envelope. Do not create a twin invoice because viewed arrived twice. After five failed attempts the log stops trying that delivery. Fix the URL or the handler, then wait for the next real event. Do not void an envelope just to generate traffic.

Save the URL. Send one envelope. Watch the last-12 log. Verify the signature. Persist completed and the closes you actually operate on. Open a workspace on Free and point a localhost or .test handler at a real send before you promise a production destination. The FAQ and published pricing repeat the envelope cap in the same words.

Open a workspace on Free

Billing is published, not charging. Send an envelope from the desk without a card.

Open a workspace