Package Information
Documentation
n8n-nodes-calyx-voe
A custom n8n community node that fills a Written Verification of Employment
(WVOE) submission onto the standardized Calyx voe.frm (5/97) PDF and
embeds the verifier signature.
- Pure
pdf-lib— no external API, no SaaS dependency. - Bundles the Calyx VOE template inside the package; nothing to host.
- Lender-agnostic — pass your lender name, address, and signer details via
node parameters. - One node, one operation: drop it in the workflow, pass the normalized
submission, get back a filled-and-signed PDF as a binary attachment.
Why this exists
n8n Cloud's Code-node sandbox disallows require('pdf-lib') (and every other
PDF library). Community nodes run at the n8n process level, outside that
sandbox — so wrapping pdf-lib in a community node is the only way to do
in-cloud PDF form filling without standing up an external service.
Install (n8n Cloud)
Community-node install on n8n Cloud requires a plan tier that supports custom
nodes — check your Settings → Community Nodes page; if the install button is
present, you can proceed.
- Open n8n Cloud → Settings → Community Nodes.
- Click Install a community node.
- Paste the package name:
n8n-nodes-calyx-voe - Tick "I understand the risks" and click Install.
- After install, the node appears in the node search as Fill Calyx VOE PDF.
Install (self-hosted n8n)
cd ~/.n8n # or wherever your n8n install lives
npm install n8n-nodes-calyx-voe
# restart n8n
Use
Drop Fill Calyx VOE PDF into a workflow immediately downstream of the node
that produces the normalized WVOE submission JSON.
Required node parameters (your lender block)
| Parameter | Stamped into |
|---|---|
| Lender Name | Box 2 line 1 |
| Lender Street Address | Box 2 line 2 |
| Lender City, State, Zip | Box 2 line 3 |
| Box 3 — Signature of Lender (Text) | Box 3 — the Calyx form expects a graphic signature; this node text-stamps instead. Use a desk name or specific person. |
| Box 4 — Title | Box 4 — title of the box-3 signer |
These five parameters travel with the node, so the package itself stays
lender-agnostic. Your lender's specific values live only inside your private
n8n workflow.
Optional node parameters
| Parameter | Default | Notes |
|---|---|---|
| Signature URL Property | verifier_signature_url |
Name of the $json field carrying the verifier signature URL or data: URI. Blank to skip embed. |
| Output Binary Property | data |
Name of the binary property the filled PDF is written to. Use data so downstream attachment nodes pick it up. |
| File Name | =voe-{{ ... borrower_name ... }}.pdf |
Output PDF filename. Expressions supported. |
Submission fields the node reads from $json
All optional except where the PDF box is required.
| Field | Goes into |
|---|---|
borrower_name |
Box 7 (Applicant Name) |
badge_number |
Box 7 (Badge # subline) |
employer_name |
Box 1 line 1 (To: Employer) |
employer_address |
Box 1 lines 2-4 (newline-separated) |
request_id |
Box 6 (Lender's No.) |
position_title |
Box 10 |
continued_employment |
Box 11 |
start_date (YYYY-MM-DD) |
Box 9 / Box 21 |
end_date (YYYY-MM-DD) |
Box 22 |
base_pay_rate |
Box 12A |
base_pay_frequency |
Box 12A checkbox (Annual / Monthly / Weekly / Hourly / Bi-weekly / Semi-monthly) |
has_overtime (Yes/No) |
Box 14 OT row |
has_bonus (Yes/No) |
Box 14 Bonus row |
ytd_gross |
Box 12B Total row, YTD |
ytd_pay_period_end_date |
Box 12B "Thru" date |
last_full_year_gross |
Box 12B Total row, Past Year |
year_prior_gross |
Box 12B Total row, Prior Year |
ot_ytd / ot_last_12mo / ot_year_prior |
Box 12B OT row |
bonus_ytd / bonus_last_12mo / bonus_year_prior |
Box 12B Bonus row |
commission_ytd / ..._last_12mo / ..._year_prior |
Box 12B Comm row |
avg_hours_per_week |
Box 15 |
next_pay_increase_date |
Box 16 |
next_pay_increase_amount |
Box 17 |
last_pay_increase_date |
Box 18 |
last_pay_increase_amount |
Box 19 |
remarks |
Box 20 |
employment_status |
Triggers Part III when "No longer employed" |
final_partial_year_earnings |
Box 23 (when previous-employer) |
separation_reason |
Box 24 |
final_position |
Box 25 |
verifier_signature_url |
Box 26 (PNG/JPG via URL or data: URI) |
verifier_title |
Box 27 |
verifier_name |
Box 29 |
verifier_phone |
Box 30 |
verifier_email |
Right of Box 30 (small) |
The base-pay total in box 12B is derived by subtracting OT/bonus/commission
from *_gross for each column, so HR's reported gross-earnings figure stays
the authoritative total.
Outputs
$json.calyx_voe_filled: true$json.calyx_voe_filename: 'voe-…pdf'$json.calyx_voe_byte_length: <bytes>$binary[<Output Binary Property>]: the filled PDF, MIMEapplication/pdf
Wire the next node — typically a Microsoft Outlook or Gmail send — to attach
the binary by the property name you chose (default data).
Coordinate tuning
If a field is misaligned on a real signed form, edit the matching top value
in nodes/CalyxVoe/fillVoe.ts (boxes are labeled inline), rebuild, republish.
License
MIT.