Skip to content

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.

Terminal window
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.

Terminal window
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"}.

Terminal window
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.

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.