Building a platform

Build a Multi-Candidate Job Application Platform With One API Account

Manage candidate-specific profiles, documents, submissions, answer rounds, and webhook updates under centralized API billing.

By Apply Guy · · 3 min read

The short answer

Give each candidate a stable candidateId, attach documents to that candidate, and select the exact resume and cover letter on each application. Keep billing centralized while preserving candidate-specific state.

Model a candidate independently from your developer account

Create a candidate with an externalId that maps to your own user record and candidateContext containing that person's information. Address, LinkedIn, education, experience, and preferences belong to that candidate's context rather than a shared account-wide profile.

Retain the returned candidate ID in your database. Creating the same person again for every application makes document selection and status attribution harder. Use your own authenticated backend to decide which of your users may act on each candidate; do not expose a shared developer API key in a browser.

Select documents per application

Upload a resume or cover letter to the candidate's document endpoint. Keep the returned document ID with the job and document version it was created for. Pass resumeId and, when appropriate, coverLetterId alongside candidateId when creating the application.

A candidate's default resume is convenient for repeated applications, but changing a shared default is a poor way to coordinate concurrent tailored applications. Explicit document selection makes each intended submission reviewable. Document ownership and purpose must match the candidate and request.

Node.js · upload one tailored resume and check readiness
import { readFile } from "node:fs/promises";
import { ApplyGuy } from "@applyguy/sdk";

const apiKey = process.env.APPLYGUY_API_KEY;
const candidateId = process.env.CANDIDATE_ID;
const jobId = process.env.JOB_ID;
if (!apiKey || !candidateId || !jobId) throw new Error("Missing environment variables");
const client = new ApplyGuy({ apiKey });
const file = new Blob([await readFile("./tailored-resume.pdf")], { type: "application/pdf" });
const { data: resume } = await client.candidates.uploadDocument(
  candidateId, "resume", file, "tailored-resume.pdf",
);
const { data: check } = await client.applications.preflight({
  candidateId, jobId, resumeId: resume.id, mode: "managed",
});
console.log({ resumeId: resume.id, ready: check.ready, cost: check.cost });
// This example uploads a document and checks readiness; it does not submit.

Track one application resource through its lifecycle

After candidate approval, create the application with a stable idempotency key and persist its returned ID. Store the candidate and job mapping in your own system as well. A queue acknowledgement is not a successful employer submission.

Use application status retrieval or webhook events to update your UI. Verify webhook signatures according to the current reference, handle duplicate deliveries, and avoid letting a delayed event overwrite a newer known state. Present failures and verification requirements accurately instead of retrying every outcome automatically.

Keep your own AI and candidate verification separate

Agent mode can pause an application with a discovered answer request. Use its prompt, schema, request ID, and fingerprint with your own model, then return validated answers through the documented endpoint. Do not invent form questions before discovery or treat one answer round as the entire application.

Email integration is candidate-specific where required. Connect only the mailbox the candidate has authorized and follow the supported setup. Secret fields are not part of ordinary candidate profile reads; your own service must also prevent logging credentials, exposing them to other users, or including them in analytics.

Keep billing central and usage attributable

API credits belong to the developer account. Map applications and document versions back to your users so your own dashboard can explain who applied, which material was used, and the result. Read current costs from the API and documentation rather than baking an old price into a long-lived integration.

Start with a small authorized end-to-end test across the ATSs your users actually need. Validate profile completeness, supported US targets, documents, inbox requirements, answer rounds, and terminal results before opening submission to a larger audience.

Sources and further reading

Provider and employer requirements can change. Follow the instructions for the particular application or integration.

Keep reading