// Developers

Drop Range Waiver
into your platform.

Build it in an afternoon. POS, eCommerce, range-management — one bearer key, one POST to mint a signing link, one webhook when the signer is done. The audit-packet PDF is signed and ready for your customer file.

// v1 · base url: app.rangewaiver.com · openapi.json

// Mental model

Two steps, one webhook.

Range Waiver gives you a signed bearer key per Range Waiver business. You mint a signing link scoped to that business, pass your customer to it, and receive a webhook when they finish. The signed audit-packet PDF arrives in the same payload.

01

Mint a signing link

POST /api/v1/signing-links with the template + optional prefill + your external_customer_id. Returns a short-lived signing URL.

02

Send the customer

Open the URL on a kiosk, a phone, or inside an iframe via the embed widget. We handle signature canvas, ID scan, photo, attestations.

03

Handle the webhook

waiver.signed arrives with the full record + a 24-hour signed PDF URL. Verify the HMAC signature, attach the PDF to your customer file, done.

// Authentication

Bearer keys. One per business.

Your Range Waiver customer generates an API key in their admin under API keys. The plaintext secret is shown exactly once — they paste it into your installation form. We store only the SHA-256 hash.

// every request
GET /api/v1/waivers
Host: app.rangewaiver.com
Authorization: Bearer rw_abcd1234_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Format: rw_<prefix>_<secret> — prefix shown in admin for identification.
  • Revocation is immediate. Lost a secret? Revoke and reissue.
  • Rate limits: 10 req/s, 300 req/min. 429 responses carry standard X-RateLimit-* headers.

// REST · v1

The endpoints you'll actually use.

POST/api/v1/signing-links

Mint a signing URL

The workhorse. Returns a signed URL the signer opens. Pass prefill data + your external id; we echo it back on the webhook so the integration stays stateless on your side.

curl -X POST https://app.rangewaiver.com/api/v1/signing-links \
  -H "Authorization: Bearer $RW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_public_id": "8c3d-...-uuid",
    "location_id": 42,
    "expires_in": "1h",
    "external_customer_id": "pos-customer-12345",
    "return_url": "https://your-pos.example.com/lanes/3?signed=1",
    "prefill": {
      "first_name": "Jane",
      "last_name":  "Doe",
      "email":      "jane@example.com",
      "phone":      "+12055550100",
      "dob":        "1990-04-12"
    },
    "metadata": { "lane": "3", "ticket_id": "abc" }
  }'

# response
{
  "url":        "https://app.rangewaiver.com/sign/eyJhbGciOi...",
  "token":      "eyJhbGciOi...",
  "expires_in": "1h"
}
GET/api/v1/templates

List templates

The template_public_id you pass to /signing-links comes from here. Stable across renames + version bumps.

{
  "data": [
    {
      "id":         123,
      "public_id":  "8c3d-...-uuid",
      "title":      "Range Liability Waiver",
      "version":    4,
      "active":     true,
      "updated_at": "2026-05-26T13:32:00Z"
    }
  ]
}
GET/api/v1/waivers

List signed waivers

Paginated. Use this to reconcile if you missed a webhook.

GET /api/v1/waivers?limit=50&offset=0

{
  "data": [
    {
      "id":          9001,
      "first_name":  "Jane",
      "last_name":   "Doe",
      "email":       "jane@example.com",
      "phone":       "+12055550100",
      "signed_at":   "2026-05-26T13:32:00Z",
      "packet_hash": "sha256:b3f0...",
      "template_id": 123,
      "location_id": 42
    }
  ],
  "limit":  50,
  "offset": 0
}
GET/api/v1/waivers/[id]/pdf

Audit-packet PDF

302 to a 15-minute signed CloudFront URL. Follow the redirect or hand the URL straight to the user. The same URL arrives pre-signed (24h) inside waiver.signed webhooks.

HTTP/1.1 302 Found
Location: https://cdn.rangewaiver.com/packets/...?signature=...&expires=...
GET/api/v1/customers

Customer search (collapsed by identity)

Returns one row per (first_name, last_name, email) tuple. Use this before minting a new signing link to surface "Welcome back" UX.

GET /api/v1/customers?q=jane@example.com&limit=25

{
  "data": [
    {
      "first_name":       "Jane",
      "last_name":        "Doe",
      "email":            "jane@example.com",
      "phone":            "+12055550100",
      "last_signed_at":   "2026-05-26T13:32:00Z",
      "signed_count":     4,
      "latest_waiver_id": 9001
    }
  ]
}
/api/v1/webhook-endpoints

Webhook endpoint CRUD

GET / POST / PATCH / DELETE. The HMAC secret is returned ONCE on POST — capture it. Generally easier to manage from the admin UI.

POST /api/v1/webhook-endpoints
{
  "url":    "https://your-platform.com/integrations/rangewaiver/wh",
  "events": ["waiver.signed", "incident.created"],
  "active": true
}

# response
{
  "id":     17,
  "url":    "https://your-platform.com/integrations/rangewaiver/wh",
  "events": ["waiver.signed", "incident.created"],
  "active": true,
  "secret": "whsec_3f0a..."   // shown once — store securely
}

// Webhooks

At-least-once. HMAC-signed. Retried 5×.

Three events. JSON. HMAC-SHA256 in X-RangeWaiver-Signature. Idempotent on delivery_id. Retries on non-2xx or timeout with exponential backoff (1s → 10s → 1m → 10m → 1h).

waiver.signed

New signing completed via web link, kiosk, or embed widget.

waiver.reattested

Returning customer re-affirmed the safety blocks per template cadence.

incident.created

RSO or admin filed an incident report from the kiosk or admin.

// waiver.signed payload
POST https://your-platform.com/integrations/rangewaiver/wh
X-RangeWaiver-Event:       waiver.signed
X-RangeWaiver-Delivery-Id: 8821
X-RangeWaiver-Signature:   3a9e...   // hmac-sha256(body, whsec_...)
Content-Type:              application/json

{
  "event":         "waiver.signed",
  "event_version": 1,
  "delivery_id":   8821,
  "timestamp":     "2026-05-26T13:32:00.123Z",
  "data": {
    "waiver_id":           9001,
    "template_id":         123,
    "template_version":    4,
    "location_id":         42,
    "first_name":          "Jane",
    "last_name":           "Doe",
    "email":               "jane@example.com",
    "phone":               "+12055550100",
    "dob":                 "1990-04-12",
    "signed_at":           "2026-05-26T13:32:00Z",
    "packet_hash":         "sha256:b3f0...",
    "audit_packet_url":    "https://cdn.rangewaiver.com/packets/...",
    "external_customer_id": "pos-customer-12345",
    "metadata":            { "lane": "3", "ticket_id": "abc" }
  }
}
// signature verification (node.js)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyRangeWaiverSignature(
  rawBody: string,
  header: string,
  secret: string,
): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(header, "utf8");
  const b = Buffer.from(expected, "utf8");
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}

// Embed widget

One script tag. Drop the signing flow anywhere.

For eCommerce checkout and customer-facing portals. The script injects an iframe + handles height resizing via postMessage. Templates must be active.

// on any page
<script
  src="https://app.rangewaiver.com/embed.js"
  data-template="8c3d-the-template-public-id"></script>
// listen for completion (Phase 2)
window.addEventListener("message", (e) => {
  if (e.origin !== "https://app.rangewaiver.com") return;
  if (e.data?.kind === "rw:signed") {
    // e.data.waiver_id, e.data.signed_at, e.data.external_customer_id
    unlockCheckout();
  }
});

// What's next

Roadmap.

Phase 1.5Sandbox env (sandbox.rangewaiver.com)planned
Phase 1.5prefill / external_customer_id / return_url / metadata on POST /signing-linksplanned
Phase 1.5Extended waiver.signed payload + event_version + Send-test-event buttonplanned
Phase 1.5X-Idempotency-Key on POSTsplanned
Phase 1.5OpenAPI 3.1 spec at /api/v1/openapi.jsonplanned
Phase 2JS SDK + rw:signed postMessage eventplanned
Phase 2Shopify Checkout Extension reference buildplanned
Phase 3OAuth-app marketplace + per-install scopesplanned

// ready to build?

Ship it this afternoon.

Sign up free, generate an API key from your admin, point your sandbox at our endpoints. Need help? Email integrations@rangewaiver.com.