When to use
Enable self-certification
Turn on self-certification per Customization Template in the dashboard, under Self-certification. The Enable self-employment income toggle chooses what the user certifies:Retrieve certification results [Server-side]
Certification data is returned by the standard order-read endpoint, gated behind thecertification query parameter. Call it after the user completes their review — the certification-completed webhook signals when results are ready.
Certification modes
Records the user flags as not their own income are excluded in both modes.
Response structure
Each retrieved record carries acertification object inline. What’s certified depends on the template configuration — an order is one configuration or the other, never both.
Bank income configuration. Payroll employments carry a certification under employers[].employments[]. Bank-detected income carries one under financial_accounts[].bank_income_sources[], and user-added income under financial_accounts[].additional_income_sources[]. Bank accounts[] are not certified in this configuration — they carry no certification object.
accounts[] carry a certification. Account certifications hold decision, rejection_reason, and rejection_comment only — they never include certified_data, and bank_income_sources / additional_income_sources are not certified.
certified_data is the user-attested snapshot. Its numeric fields can be null — a payroll employment may report hours_per_month while leaving monthly_income empty.Decision values
Rejection reasons
When the decision isnot_representative, the certification object includes a rejection_reason:
Certified data
Where present,certified_data is the user-attested snapshot recorded at certification time.
Read the income figure
Mirror the logic the certification screen uses to pick the income amount:- If
certified_data.typeisself_employment, usecertified_data.monthly_income(gig and bank-detected income). - Otherwise (
type: employment), useemployments[].pay_rate; if it’snull(typically hourly), fall back to the latest statement’sgross_pay(employments[].statements[0].gross_pay). Always read this amount together withemployments[].pay_frequency—pay_rateandgross_payare per-pay-period values, so they’re only meaningful paired with the frequency (W,BW,SM,M, …).
certified_data.monthly_income is populated only for self_employment; for W-2 it’s null, which is why step 2 reads the amount from the report.
Hours per month
certified_data.hours_per_month can be null if it can’t be calculated. Truv calculates it as follows.
“Recent pay stubs” below means every pay stub dated in the last 6 weeks with a non-zero hours value. There’s no cap on how many pay stubs that can include.
Payroll employees (salaried or hourly):
If the employee has a known hourly rate and has recent pay stubs, hours_per_month is the total hours from those pay stubs, extrapolated to a 30-day month. Pay frequency doesn’t matter here, even if it’s known: this check runs first and overrides everything below.
Otherwise:
- If there are recent pay stubs, average their hours per pay stub, then × pay frequency ÷ 12 if pay frequency is known. If frequency isn’t known, use the total recent-pay-stub hours extrapolated to a 30-day month instead.
- If there are no recent pay stubs but the hourly rate is known: monthly income ÷ hourly rate.
- If only a pay rate is known (no recent pay stubs or hourly rate): assume a standard full-time month, 174 hours (40 hrs/week × 52 weeks ÷ 12 = 173.33, rounded up).
- If monthly income is known: monthly income ÷ federal minimum wage ($7.25/hour), rounded up.
- Otherwise:
null.
null if there are no recent pay stubs with hours.
Volunteers:
- If they have pay stubs older than the last 30 days: sum of hours reported within the last 30 days.
- If not, and they’ve been active more than 30 days: total logged hours since they started, pro-rated to 30 days (e.g., 60 hours over 60 days = 30 hours/month).
- Otherwise (active 30 days or less, or no start date on file): total logged hours, as-is.
null if there’s no income amount to estimate from.
Next steps
Follow-up
Re-engage users who didn’t finish verification
Embedded Orders
Full embedded orders implementation guide