Payerworks writes and explains files; it sends nothing to a payer. Every file a route writes says transmitted: false, and is yours to send on your own connection. A test key is for invented data only, never a real patient.
What you need
- A test key, from the developers page. It is for invented data only.
- Node 18 or later, the JavaScript client payerworks.mjs, and sample-data.mjs, the invented patient and clinic every example uses, in one folder.
- Two environment variables:
PAYERWORKS_API_KEY(your key) andPAYERWORKS_BASE_URL(the base URL shown with your key).
The steps
- 1. Write the question as a 270 with POST /v1/eligibility/270: the payer, the provider, the subscriber, the day and the service types, as the JSON most clearinghouse APIs take. The 270 is yours to send on your own connection.
- 2. Send the same question to the eligibility sandbox (POST /v1/sandbox/eligibility). It answers as a payer would, with a 271 in
files.eligibility_271. - 3. Explain that 271 with POST /v1/eligibility/explain, naming what you asked about in
asked. Readmembers[0].coverage.state, then each service’s deductible and out-of-pocket figures, in and out of network. - 4. A member ID ending in NOTFOUND is not found, BADDOB has a birth date that does not match: each refusal is said as its reason and the field to fix.
The code
eligibility.mjs runs every step below against the API with a test key. It needs payerworks.mjs and sample-data.mjs beside it.
// Payerworks example: eligibility, a 270 written and a 271 explained. Docs: https://payerworks.com/docs/eligibility
//
// Run it with Node 18 or later, with the JavaScript client (https://payerworks.com/sdk/payerworks.mjs)
// and sample-data.mjs beside this file:
// PAYERWORKS_API_KEY=pw_test_... PAYERWORKS_BASE_URL=<the base URL shown with your key> node eligibility.mjs
// A test key and invented data only. Payerworks sends nothing to a payer: every file it writes is yours.
import { pathToFileURL } from 'node:url';
import { Payerworks, PayerworksError } from './payerworks.mjs';
import { ELIGIBILITY_QUESTION, SENDER_ID, PAYER_ID, copy, endingIn, refusalOf } from './sample-data.mjs';
/** @param {Payerworks} pw */
export async function run(pw) {
// 1. Write the question as a 270. The file is yours to send on your own connection.
const written = await pw.postEligibility270({ sender_id: SENDER_ID, receiver_id: PAYER_ID, control_number: 12, request: copy(ELIGIBILITY_QUESTION) });
// 2. The eligibility sandbox answers the same question as a payer would: a 270 and its 271.
const sandbox = await pw.postSandboxEligibility({ request: copy(ELIGIBILITY_QUESTION) });
const the271 = sandbox.files.eligibility_271;
// 3. Explain the 271 per patient, for the services and the day you asked about.
const explained = await pw.postEligibilityExplain({ x12: the271, asked: { service_type_codes: ['30'], date_of_service: '2026-10-20' } });
const member = explained.members[0];
// 4. A member ID ending in NOTFOUND: the payer cannot find the subscriber, and the answer says why in words.
const notFound = await pw.postSandboxEligibility({ request: endingIn(ELIGIBILITY_QUESTION, 'NOTFOUND') });
// 5. The failure path: an NPI that fails its check digit is refused before anything is written.
const refused = await refusalOf(() => pw.postEligibility270({
sender_id: SENDER_ID, receiver_id: PAYER_ID, control_number: 13,
request: { ...copy(ELIGIBILITY_QUESTION), provider: { organizationName: 'SAMPLE FAMILY MEDICINE', npi: '1234567890' } },
}), { PayerworksError });
return {
written: { transmitted: written.transmitted, starts: written.x12.slice(0, 3) },
coverage: member.coverage.state,
not_found: notFound.outcomes[0].outcome,
refused,
};
}
// Run as a script: node <this file>, with PAYERWORKS_API_KEY and PAYERWORKS_BASE_URL set.
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
console.log(JSON.stringify(await run(new Payerworks()), null, 2));
}
{
"written": {
"transmitted": false,
"starts": "ISA"
},
"coverage": "active",
"not_found": "subscriber_not_found",
"refused": {
"status": 422,
"code": "invalid_requests",
"request_id": "req_5"
}
}What you should see
coverageis active;not_foundis the sandbox’s outcome for NOTFOUND;refusedis a 270 with an NPI that fails its check digit, refused before anything is written.
Next
- Use a real 271 the same way: explain accepts any 271, as X12 or as JSON. Eligibility has every field.