Prepare and file Form 1099-R (Distributions From Pensions, Annuities, Retirement Plans) with the IRS via IRIS. We don't keep recipient SSNs or amounts after filing (review drafts from your API tools are encrypted and deleted when you pay or after 7 days) — save your data locally as JSON to re-file.
Terms of Use · Privacy Notice
Quick start
# 1) Validate
curl -s -X POST /api/v1/iris/1099-r/validate \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"tax_year":2026,"records":[...]}'
# 2) Create submission (billing)
curl -s -X POST /api/v1/iris/1099-r/submissions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Idempotency-Key: my-run-001" \
-H "Content-Type: application/json" \
-d '{"tax_year":2026,"email":"you@example.com",
"payer_authorization":{"relationship":"tpa","attest":true},"records":[...]}'
# 3) Transmit (resend full records[])
curl -s -X POST /api/v1/iris/1099-r/submissions/123/transmit \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"records":[...],"payment_intent":"pi_..."}'
# 4) Poll IRS acknowledgement
curl -s -X POST /api/v1/iris/1099-r/submissions/123/acknowledgement \
-H "Authorization: Bearer YOUR_KEY"
# 5) Correction feedback (annotate your records with _errors)
curl -s -X POST /api/v1/iris/1099-r/submissions/123/correction-feedback \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"records":[...]}'
# 6) Re-transmit correction
curl -s -X POST /api/v1/iris/1099-r/submissions/124/transmit \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"transmission_type":"C","prior_utid":"...","records":[...]}'
Every successful transmit returns record_ids, one entry per input record, in the same order.
Save the irs_utid, irs_submission_id, irs_record_id, and irs_unique_record_id fields on each record.
To correct a record, send the complete corrected record with those fields included.
Once the IRS has accepted the transmission, the server builds the record's UniqueRecordId (ReceiptId|SubmissionId|RecordId).
Until then, it uses the irs_unique_record_id you sent.
Corrections whose records have neither are rejected before billing.
payer_authorization is required on every submission. relationship is one of
self, tpa, cpa, actuary, software_partner, other, and attest: true records this statement for each payer:
I confirm that, for each payer in this filing, I am the payer or I am authorized by the payer to file its Forms 1099-R with the IRS, that I can provide written authorization on request, and that the information is true, correct, and complete to the best of my knowledge.
State filing (CF/SF). state_filing on POST /validate and POST /1099-r/submissions is
cfsf (default: the IRS forwards each form to the participating states in box13_state and box13_state_2, under the Combined Federal/State Filing program) or
self (federal only; you file with the states). The choice is locked when the submission is created; transmit uses it.
Set cfsf_opt_out: "1" on a record to keep that form from being forwarded.
A form has two state/local lines: the second uses the _2 fields (box12_state_withheld_2, box13_state_2, box13_state_no_2,
box14_state_dist_2, box15_local_withheld_2, box16_locality_2, box17_local_dist_2), and its state must differ from the first.
Validate and transmit responses include cfsf_summary (form counts per state: forwarded, self_file, no_tax, no_state,
and direct for participating states that also want the form filed with them) plus state_direct_notes in plain language,
and validate returns non-blocking warnings, such as a forwarded form without the payer's state ID.
See State filing for participating states and what the IRS doesn't cover.
Pricing. Validate and submission responses include a quote (gross_cents, credit_cents,
waived_cents, net_cents, lines). Account credit is applied automatically. Corrections are new, paid
submissions unless we marked the original as a service fault; then send parent_submission_id and that one is free.
Transmitting an unpaid submission returns 402.
Rejected submissions: send a replacement (free). When the IRS rejects a submission (status Rejected, or
PartiallyAccepted when only some payers were rejected), don't send the forms again as new forms and don't file a correction: the IRS requires a
replacement. Create a new submission with "transmission_type":"R" and "replaces_submission_id" set to the rejected one,
with the fixed records, then transmit it. For Rejected, include every record of the rejected submission; for PartiallyAccepted, include only the
rejected payers (replacement.rejected_payer_submission_ids on the rejected submission lists their positions; replacement.payer_results has each payer's result).
The server adds the IRS link (OriginalReceiptId or OriginalUniqueSubmissionId) and keeps it pointing at the earliest rejected original if a replacement is itself rejected.
Replacements are free up to the rejected submission's form count. If the IRS accepts the replacement within 60 days of the rejection
(replacement.deadline), the forms count as filed on the original date. Exceptions: a rejected correction is filed again as a correction,
an XML-schema rejection is filed again as an original, and in the IRS test system (ATS) rejected test filings are resubmitted as originals.
Transmitting a production submission the IRS rejected returns 409 with replaces_submission_id.
# Replace rejected submission 123 (free), then transmit the new one
curl -s -X POST /api/v1/iris/1099-r/submissions \
-H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"tax_year":2026,"transmission_type":"R","replaces_submission_id":123,"payer_authorization":{"relationship":"tpa","attest":true},"records":[...]}'
curl -s -X POST /api/v1/iris/1099-r/submissions/125/transmit \
-H "Authorization: Bearer YOUR_KEY" -d '{"records":[...]}'
AI assistants and review drafts
Let an AI assistant or other software prepare 1099-Rs without being able to file them. Create a key with the
validate and prepare drafts for my review permission. The assistant sends the forms; you get a review link, sign in,
check every form on the Prepare page, pay, and file. Drafts are encrypted with a key derived from the link (we keep only a hash),
open only for the key's account owner, and are deleted when you pay or after 7 days.
# Field names and rules for a tax year (no key needed)
curl -s "/api/v1/iris/1099-r/fields?tax_year=2026"
# Create a review draft (key with the draft permission)
curl -s -X POST /api/v1/iris/1099-r/drafts \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"tax_year":2026,"label":"Plan X distributions","state_filing":"cfsf","records":[...]}'
# → {"draft":{"id":"drf_...","status":"open","expires_at":"..."},"review_url":"https://...","validation":{...}}
# Give the review_url to the user; it is shown only once.
# Check or delete it
curl -s /api/v1/iris/1099-r/drafts/drf_... -H "Authorization: Bearer YOUR_KEY"
curl -s -X DELETE /api/v1/iris/1099-r/drafts/drf_... -H "Authorization: Bearer YOUR_KEY"
MCP. Assistants that support MCP servers (Claude, ChatGPT connectors, Cursor, and others) can use the same tools at
https://pensionresource.website/api/v1/iris/mcp with the key as a Bearer token. Tools:
get_field_reference, validate_1099r, create_review_draft, get_draft_status.
A plain-text guide for AI tools is at
/llms.txt.
{
"mcpServers": {
"pensionresource-1099r": {
"url": "https://pensionresource.website/api/v1/iris/mcp",
"headers": { "Authorization": "Bearer YOUR_DRAFT_KEY" }
}
}
}