Dynamic Number Insertion
DNI is a public, CORS-enabled browser API at /hooks/dni.php. Its pool key is intentionally low-trust—similar to an analytics measurement ID—not a secret. All actions use POST; OPTIONS preflight returns 204.
Lease a number
Section titled “Lease a number”curl --fail-with-body -X POST \ "https://app.dialdozer.com/hooks/dni.php?action=lease" \ -H "Content-Type: application/json" \ -d '{ "pool":"web-solar-phx", "visitor":"v_9eM2fK", "utm":{"source":"google","medium":"cpc","campaign":"summer","term":"solar quote","content":"hero-a"}, "gclid":"example-click-id", "landing":"https://example.com/solar?utm_source=google", "referrer":"https://www.google.com/" }'{ "ok":true, "number":"16025550177", "formatted":"(602) 555-0177", "ttl":900, "fallback":false, "placeholder":"16025550100", "placeholder_formatted":"(602) 555-0100"}pool and visitor are limited to 48 characters; visitor IDs retain only letters, digits, _, and -. Returning visitors renew their existing hold. An exhausted pool returns HTTP 200 with fallback: true and the configured fallback number. Attribution is first-touch: later lease calls update visit time/user agent but do not replace original UTM/click/landing/referrer values.
Heartbeat a lease
Section titled “Heartbeat a lease”curl --fail-with-body -X POST \ "https://app.dialdozer.com/hooks/dni.php?action=heartbeat" \ -H "Content-Type: application/json" \ -d '{"pool":"web-solar-phx","visitor":"v_9eM2fK"}'Success is {"ok":true,"ttl":900}. A valid visitor without an active hold returns HTTP 200 {"ok":false,"error":"not_leased"}.
Record a browser event
Section titled “Record a browser event”curl --fail-with-body -X POST \ "https://app.dialdozer.com/hooks/dni.php?action=event" \ -H "Content-Type: application/json" \ -d '{"pool":"web-solar-phx","visitor":"v_9eM2fK","kind":"form","name":"quote-submit","value":1,"meta":{"variant":"hero-a"}}'Allowed online kinds are pageview, form, and custom; unknown kinds are coerced to custom. name is capped at 80 characters. Numeric value defaults to 0. Object meta is stored only when its encoded JSON is no larger than 4,000 bytes; otherwise it is silently omitted. Request bodies are capped at 65,536 bytes; oversized/invalid bodies eventually fail field validation rather than returning a dedicated body-size error.
Privacy and limits
Section titled “Privacy and limits”Raw IP addresses are not stored by this endpoint. Dial Dozer stores SHA-1 of salt|IP; configure a unique NPK_IP_SALT because the source fallback salt is static. All DNI actions share 3,600 requests/hour per hashed IP in a fixed window. Invalid pool returns 404 pool_not_found; missing visitor returns 422 visitor_required; non-POST returns 405.