The contracts row carries a full pair of signature blocks: customer_signer_name/email/phone, customer_signature_image, customer_signed_at, customer_ip_address, customer_user_agent — and the same six for the counter-signer plus counter_signer_user_id. Per-section initials carry their own per-section timestamps.
Also called: signature audit · IP address on contract · proof of signing · timestamp
- 1The sign route reads the IP from x-forwarded-for (first hop) or x-real-ip, and the user agent from the request headers.
- 2Email is lowercased and trimmed; phone is reduced to digits before storage.
- 3The counter-sign path records the signing user's id so the counter-signer of record is a specific person.
- 4The public customer-facing read deliberately omits the audit fields: it 'Returns only the fields needed to render the contract page — not the full audit trail.'
The route header names the purpose: 'The customer's IP is captured for the audit trail; user_agent comes from the request headers.' The complementary restraint on the public read exists so the evidence trail isn't served to anyone holding the link.
- Signatures with no supporting metadata
- Audit data exposed on a public endpoint
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →