How document fingerprints work
What the fingerprint on a tenant.ph document is, how to check it, and what it does and doesn't prove.
What a fingerprint is
A fingerprint (technically a SHA-256 hash) is a code of 64 characters, digits and the letters a to f, worked out from a document. Change one comma and the fingerprint comes out completely different, so a document that gives the same fingerprint hasn't changed. tenant.ph keeps two kinds.
- The content fingerprint is printed at the foot of every billing statement, deposit settlement, completed inspection and lease contract. It's worked out from the document's details as tenant.ph recorded them, not from any file, so a printed or re-saved copy keeps it.
- The file fingerprint is worked out from a PDF's exact bytes, so saving or printing the PDF again changes it. For billing statements and deposit settlements it's in the email the PDF came with and on the document's page. For contracts, inspection reports and uploaded files, drop the file on Check a document.
What a fingerprint doesn't prove
- It isn't a signature. A match proves the document is the one in tenant.ph's records, unchanged. It doesn't prove who wrote it, and it doesn't stop tenant.ph from changing a record and its fingerprint together.
- It doesn't prove the content is true. A statement's charges, an inspection's conditions, a settlement's deductions are what the landlord entered. A tenant can dispute an inspection or settlement, and the answer is kept with it.
- A fingerprint on its own proves nothing about a paper. Anyone can copy a real fingerprint onto a changed page. Check that what the fingerprint stands for matches the paper you hold (step 3 below).
- An uploaded document is only the same file. tenant.ph vouches that a file is the one uploaded, not for what it says.
- It isn't a timestamp. The dates are tenant.ph's own, not a third party's.
- It isn't a tax document. Billing statements are not BIR official receipts or invoices.
Checking a document
Only the landlord and the tenants on a lease can check its documents on tenant.ph. If someone handed you a document, ask them to check it in tenant.ph with you, or to send you its "Hashed data" file.
- On tenant.ph. Logged in, open Check a document and drop the PDF, or paste the fingerprint printed on it. It looks among the documents of your own leases, as landlord or tenant.
-
Or hash it yourself.
On the document's page, "Hashed data" next to its fingerprint downloads the exact bytes the fingerprint was worked out from, as a JSON file. Hash that file: it must give the printed fingerprint. Upper or lower case doesn't matter.
# Mac shasum -a 256 BS-00012-content.json # Linux sha256sum BS-00012-content.json # Windows (PowerShell); it prints capitals, which is the same fingerprint Get-FileHash BS-00012-content.jsonWith Python 3, save this as check.py; it also says whether it matches and shows what the fingerprint covers:
import hashlib, json, sys data = open(sys.argv[1], "rb").read() digest = hashlib.sha256(data).hexdigest() print("Fingerprint:", digest) if len(sys.argv) > 2: expected = sys.argv[2].strip().lower() print("Matches" if digest == expected else "Doesn't match") # A readable view only: the fingerprint is of the file's raw bytes. # Objects are written as lists of [key, value] pairs sorted by key. def readable(value): if isinstance(value, list) and value and all( isinstance(p, list) and len(p) == 2 and isinstance(p[0], str) for p in value ): return {key: readable(v) for key, v in value} if isinstance(value, list): return [readable(v) for v in value] return value print(json.dumps(readable(json.loads(data)), indent=2, ensure_ascii=False))Run it as python3 check.py BS-00012-content.json <the printed fingerprint> .
- Then compare the contents. Read what the check shows (Check a document opens the document; the Python script prints it) and make sure the amounts, dates and names match the paper you were given. A real fingerprint on different content means the paper was changed.
The format
For anyone writing their own check: the content fingerprint is the SHA-256 of a JSON document written the same way every time, in tenant.ph's own canonical form (not RFC 8785).
- UTF-8, with no spaces or line breaks between values.
- Every object is written as a list of [key, value] pairs sorted by key, comparing the keys' bytes.
- Lists are in a fixed order: a statement's charges then its payments, an inspection's lines and photos as listed, a lease's parties in the order they were added, rent changes by date.
- Amounts are text in pesos with two decimals, like "18500.00"; dates are YYYY-MM-DD; ids and counts (a due day, a file size) are plain numbers; an empty value is null.
- Text is written as typed, accents and ₱ included. Only quotes, backslashes and control characters are escaped: \", \\, \n-style escapes where JSON has one, otherwise \u00XX with capital hex digits.
- Fields added since a kind of document was first issued appear only when they have a value, so every fingerprint ever issued still checks.
It covers more than is printed: record numbers that tie the document to tenant.ph's ledger (charge and payment ids, the unit, where photos are stored, inspection lines).
- Billing statement
- Its number, lease, reason, issue and due dates, landlord (email, and name, address and TIN when given), unit, address, tenants, the totals, and each line: the charge or payment id, kind, description, date and amount.
- Deposit settlement
- Its number, lease, dates, the inspection it's based on, the deposit's account, each damage line and what the deposit was applied to, the note, what was kept and why, and for a correction its revision, what it replaces and why.
- Inspection
- The lease, move-in or move-out, the date, notes, every line in order (area, item, condition, note) and, when there are photos, each photo's storage location, type, size, caption and line. Not the photos' pixels.
- Lease terms
- The terms as sent: the unit, term type and dates, rent and planned rent changes, currency, advance (and whether it's for the first or last month), deposit and the days to return it, due day, notice, utilities, special terms, late fee, early termination, household, the address, the landlord, and every party's role, name and email. Each tenant accepts the lease by this fingerprint. Later moves and agreed rent changes aren't in it, nor is the lease number: two leases with exactly the same terms have the same fingerprint.