Skip to content

Extracting Structured Fields From an Employment Verification Letter

9 min read · updated August 11, 2026

“Ms Sample’s current annual salary is $92,000.” That sentence is the entire reason the letter was requested, and on its own it does not say whether the figure includes a bonus, a commission plan, a shift differential or nothing but base pay.

A letter is a dated assertion

An employment verification letter is written on request — for a lender, a landlord, an immigration filing, a new employer — and it is prose. Four or five sentences from an HR mailbox stating that a named person is employed, in what role, since when, and at what pay. There is no form, no field labels and no fixed order, and the same employer will produce differently worded letters depending on who typed it.

The important structural property is that every statement in it is scoped to the letter’s date. “Currently employed” means as of the date at the top. So the letter date is not metadata; it is part of every field’s meaning, and an extraction that stores employment_status: active without it produces a record that becomes quietly false without changing.

The second structural property is that a letter is a summary of something that exists in structured form elsewhere. Lenders have long used dedicated verification forms with separate lines for base pay, overtime, commissions and bonuses — Fannie Mae’s Request for Verification of Employment, Form 1005, is the standard example in US mortgage lending, and the reason it separates those lines is exactly the ambiguity this page is about. The letter collapses what the form separates, and no amount of prompting recovers what the writer did not write.

The salary field is ambiguous

Take the phrasings that actually appear and what each does and does not settle:

  • “Current annual salary”. Almost certainly base for a salaried employee, but it is a convention rather than a definition, and some writers use it to mean total cash compensation.
  • “Annual base salary”. Unambiguous as to basis, silent on variable pay — which may exist and is simply not mentioned.
  • “Total annual compensation”. Includes something beyond base, but does not say what, and may or may not include equity.
  • “Currently earns $44.00 per hour”. A rate, not an annual figure. Turning it into one requires an assumed number of hours, and the common assumption of 2,080 hours — forty hours across fifty-two weeks — is an assumption about this person’s schedule that the letter did not make. If you annualise, the assumption belongs in the record as a labelled field, not buried in code.
  • “$3,538.46 semi-monthly”. A period amount, where semi-monthly (24 periods) and bi-weekly (26 periods) differ by about eight percent and are routinely confused by writers as well as readers. Extract the frequency word verbatim.

The resolution is not to guess. It is to make the basis an explicit field with an unstated value, and to keep the sentence. A downstream consumer that needs base pay specifically can then see that the letter does not provide it and request a document that does, which is a correct outcome. A pipeline that silently records the number as base pay has manufactured a certainty that never existed.

Which employment date is this?

Letters say “has been employed since” and mean at least three different things. The original hire date is when the person first started. The adjusted service date is a computed date used for benefit accrual, which can precede the hire date after an acquisition or a bridged break in service. The most recent rehire date applies where somebody left and returned. An employer’s HR system holds all three, and the letter writer picks one without saying which.

Where the letter does not distinguish, record the printed phrase in a tenure_basis_text field beside the date rather than mapping it to a canonical type you cannot support. Where it does — some letters helpfully say “continuous service since” — that phrase is worth more than the date it precedes.

Date formats add their own hazard, because these letters cross borders. A verification letter for a visa application may be written in a country using day-month-year against a reader expecting month-day-year, and any date where both components are twelve or below is genuinely ambiguous from the digits alone. If the letter contains a spelled-out month anywhere, use it to infer the convention for the whole document; otherwise mark ambiguous dates as ambiguous, which is what a date-field validation rule is for. There is no check digit here either.

Status, hours and job title

Employment status has more values than active and terminated. Full-time and part-time are different claims from employed and not, and both are different from the worker classification — employee, contractor, agency — which a verification letter from an employer implicitly asserts by existing but rarely states. Where the letter gives an FTE or a standard weekly hours figure, that is a separate numeric field and not a restatement of status.

Job title is a string and should stay one. The temptation to normalise titles into a taxonomy at extraction time is strong and wrong: the normalisation is a downstream judgement, and once you have replaced “Senior Analyst II, Risk” with a category you cannot get the original back. Keep the printed title, add a normalised field beside it if you need one, and never let the second overwrite the first.

The other fields worth structuring are the letter’s own provenance: the signatory’s name and role, the company, and whether contact details for verification were included. A letter signed by an HR director on headed paper and one signed by a colleague are the same fields with different weight, and only the signature block records the difference.

Recording ambiguity rather than resolving it

{
  "letter_date": "2026-07-15",
  "subject": { "name_as_printed": "Alex Sample" },
  "employer": { "name": "Example Industries Ltd",
                "signatory": "HR Operations Manager" },
  "employment_status": "active_as_of_letter_date",
  "employment_type": "full_time",
  "job_title_as_printed": "Senior Analyst II, Risk",
  "tenure": { "date": "2021-03-01",
              "tenure_basis_text": "has been employed since",
              "tenure_basis": "unstated" },
  "compensation": {
    "amount": 92000, "currency": "USD",
    "period": "annual",
    "basis": "unstated",
    "basis_text": "current annual salary",
    "includes_variable_pay": null,
    "annualisation_assumption": null
  },
  "verbatim": "Ms Sample's current annual salary is $92,000."
}

Every ambiguity above has become a field rather than a decision. The record now supports the two questions people actually ask of it — what did the letter say, and how confident can anyone be about what it meant — and it supports them without a human reopening the PDF.

Where an employment verification is obtained through a third-party verification service or a consumer reporting agency rather than directly from the employer, the resulting report may be a consumer report under the US Fair Credit Reporting Act, which carries permissible-purpose, disclosure and adverse-action obligations. Those obligations attach to how the information is obtained and used, not to how it is parsed. This page is about parsing; who may request one of these, and what may be done with it, is a question for the people responsible for that programme.

For the multi-source case — where the verification arrives as one section of a larger report alongside education and criminal searches — the structural problem changes, and that is the subject of extracting a background check report.