Recruit100x
Help centre
Short answers to the questions agencies ask most. Every page in the app also has a Help link that brings you here.
Roles and interview guides
Creating a role. Paste or link a job description and analyze it. Confirm the title, client, required criteria (facts like authorization or location) and evaluation criteria, then generate the interview guide. Generation usually takes under 90 seconds.
Approving the guide. Read the basics to confirm, the role questions and the assessment criteria; edit or reorder questions; approve. Invitations can only go out against an approved guide. Editing later creates a new version — candidates already invited keep the version they were invited with.
Closing a role. Unstarted invitation links stop working; interviews in progress finish. Reopen at any time from Role settings.
Invitations
Adding candidates. Type them in, upload a CSV or paste one (columns: name, email; phone and source optional). Every row is checked before anything is sent; rows with problems show the row, the field and how to fix it.
Duplicates. A candidate with a live invitation for the role can be reminded instead of re-invited; a finished one can be invited again.
Expiry. Links expire at the end of the day you chose (7 days by default). Candidates get one reminder 48 hours before. You can extend, resend or cancel from the Candidates tab.
Bounces. If an email bounces, the row says so and offers to fix the address and resend.
The candidate's interview
Candidates open the link, read the notice and consent, check their microphone, and talk with the interviewer for 15–20 minutes. They can switch to text at any point, stop and come back within the resume window, or ask for a person instead. None of those choices affects the assessment.
They receive a confirmation email when they finish, with your agency’s next-steps text if you set one under Settings → Branding.
Reports and decisions
Reading a report. Facts stated (in the candidate’s words), required criteria (Meets / Does not meet / Not confirmed), an assessment rated per criterion with quotes that play the moment in the recording, a summary, and review signals. There is no overall score.
Deciding. Advance, Hold or Do not advance — you record it with an optional note; it is saved with your name and time and can be changed later with history kept. Nothing is sent to the candidate; your own process handles that.
Comparing. Select two to four candidates on the Candidates tab to see them side by side. The order carries no meaning.
How evidence checking works
Every sentence is checked against the transcript. Before you see a report, every sentence in its summary, strengths, concerns, suggested follow-ups and criterion notes is checked against what the candidate actually said. A sentence the transcript does not support is sent back to be rewritten once, and removed if it still isn't supported. The same check runs on submittal notes, including your own edits. Quotes are always the candidate's exact words. A report that passed shows the line “Every sentence checked against the transcript.”
“Not verified.” If the automatic check could not run for a report, it says “Not verified” instead — it never claims a check that did not happen. Nothing is hidden: read the summary against the quotes, which are always taken word for word from the transcript.
“Not asked” and “Not observed.” “Not asked” means no question in this screen's guide covered the criterion, so the candidate was never asked — it is not a low mark. “Not observed” means a question did cover it, but the candidate's answers gave nothing to rate. Neither counts against the candidate.
“No evidence found in this screen.” Use “Show evidence” on any criterion or fact to see only the transcript turns that bear on it. When nothing the candidate said bears on it, the report says so plainly instead of guessing.
“Not charged.” A screen in which the candidate did not answer any planned question uses no credit. The report is still there for you, marked “Not charged” on the report and on the candidate's row.
“Ask this report” and “Ask these candidates.” Type a question the summary doesn't cover, such as “Did they mention managing a team?”. The answer is the candidate's own turns from the transcript, never a generated reply, grouped as “Answered”, “Unclear” (read them before relying on them), “Not stated” (asked, but not answered) or “Not asked”. On a role's Candidates tab, ask these candidates asks the same question across its completed reports.
Text that leaves your agency is checked too. A shortlist note, a submittal note or a decision note shared with a client is checked sentence by sentence for details that should not leave the agency, such as a health condition, age or family plans. A sentence that does is refused and shown to you with the reason; nothing is rewritten for you.
Never a score. These checks decide what is shown and what is removed; they never produce a number about the candidate. Each criterion is rated in words with the candidate's quotes, there is no overall score, and every decision stays with you.
Credits and billing
One credit is used when a candidate completes an interview. Invitations, opens and abandoned interviews are free. Pack credits never expire; monthly-plan credits roll over one cycle. Owners buy credits under Settings → Billing. A low balance never blocks access to reports you already have. Public prices are on the pricing section.
Texting candidates
What gets sent. When an owner turns texting on under Settings → Notifications, an invitation can also go out as a short text with the same link as the email, plus at most one reminder and one new-link text. Email always goes too. Each text names your agency and the role, says the interview is AI-led and reviewed by a recruiter, and ends with “Reply STOP to opt out, HELP for help.”
Who is responsible for what. Your agency is the sender of record. Before texting is turned on, an owner accepts the texting terms: your agency must have each candidate’s consent to be texted about the role, keep phone numbers accurate, and follow the messaging laws where your candidates are. Recruit100x sends the texts on your agency’s instructions, honours opt-outs at once, keeps to daytime hours and keeps a record. We may pause texting for an agency whose opt-out or complaint rates suggest consent was not obtained.
Consent on every import. On the invite step, tick the box confirming these candidates applied to the role or agreed to be texted about it. The step shows how many will also get a text and why the others won’t (no mobile number, opted out). Without the tick, invitations go by email only. Your name and the time are kept in each candidate’s compliance record.
Opting out, in any words. A candidate who replies STOP (or UNSUBSCRIBE, QUIT, END and similar), or writes something like “please don’t text me” or “wrong number”, gets no further texts from any agency on Recruit100x, and texts already waiting are cancelled. Replies in their own words are also checked by our team. Replying START opts them back in for future invitations; nothing is re-sent. HELP gets a short help message. The candidate’s profile shows “Opted out of texts”, and you can switch on “Do not text” yourself.
Timing. Texts go out only between 9:00 AM and 7:00 PM in the candidate’s own time zone, Monday to Saturday (and not on US federal holidays for US numbers). Owners can narrow those hours but not widen them. A text that would arrive outside them waits for the next opening; a reminder that would arrive too close to the link’s expiry is skipped.
Seeing what happened. Each candidate row shows an email chip and a text chip (queued, sent, delivered, failed, opted out). The candidate’s profile lists every message, and the role’s Activity tab shows texts sent and how many candidates arrived by text versus email.
Shortlists and client feedback
Sharing several candidates at once. On a role’s Candidates tab, select up to ten finished reports and choose Create shortlist. Put them in the order you want, add a short note, and choose whether the link includes recordings, review signals and your submittal notes, and when it expires (7, 14 or 30 days). The link is shown once — copy it then. You can edit or revoke it at any time from the role’s Shortlists tab.
What the client sees. A page that works on a phone: a side-by-side strip, then one card per candidate with facts in their own words, the criteria checks and the assessment with quotes. Clients never see transcripts, candidate email addresses or phone numbers, or your decisions. Views are counted.
Client answers. The client can mark each candidate Yes, Maybe or No with an optional comment and their name. You are notified (following your Reports email setting), and the latest answer shows on the candidate’s row and report. A client answer never changes your decision; you still record that yourself.
Submittal notes. A short client-ready note can be drafted from each finished report. Every figure and quote in it is checked against the report, and it only reaches a client once you approve it.
Integrations and API
Copy for ATS. You can copy a formatted summary (plain text or Markdown) from a finished report and paste it into your applicant tracking system. It always shows your current decision. Owners choose the default format under Settings → Integrations.
Submittal notes. A client-ready note is drafted from the report’s facts and evidence only. You edit and approve it before it is shared or sent anywhere.
Where to set things up. When integrations are available, owners manage Zapier and Make invites, webhooks and API keys under Settings → Integrations. Keys and signing secrets are shown once, so store them safely. Reports sent to another system include the candidate’s personal data; your agency is responsible for that system.
Webhooks
Each event is sent as an HTTPS POST with a JSON body {id, type, api_version, occurred_at, agency_id, data} (api_version 2026-09-01). Use id to ignore duplicates; events can arrive out of order. Headers follow the Standard Webhooks format: webhook-id (the delivery id), webhook-timestamp (Unix seconds), webhook-signature, plus Content-Type: application/json, User-Agent: Recruit100x-Webhooks/1 and X-Recruit100x-Event.
Delivery. Any 2xx answer within 15 seconds counts as delivered. Redirects are not followed and count as failures. Failed deliveries are retried after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours (8 attempts in all, about a day), then marked failed with no more retries. Answering 410 Gone turns the endpoint off. If every delivery to an endpoint fails for 3 days, it is turned off and owners are emailed. Every delivery can be replayed from the endpoint’s delivery log for 30 days, and “Send test event” sends a signed test.ping. Events are only kept while your agency has at least one endpoint that is on or paused; with none, nothing is stored.
Events.
invite.sent— Invitation sent (API scoperead:roles)invite.opened— Invitation opened (API scoperead:roles)screen.completed— Interview completed (API scoperead:reports)report.ready— Report ready (API scoperead:reports)report.failed— Report delayed (API scoperead:reports)decision.recorded— Decision recorded (API scoperead:reports)client_feedback.received— Client feedback received (API scoperead:reports)candidate.sms_opted_out— Candidate opted out of texts (API scoperead:roles)shortlist.created— Shortlist created (API scoperead:reports)
report.ready, report.failed and decision.recorded carry the full report, the same object GET /api/v1/reports/{id} returns. Fields may be added within a version; none are removed or renamed.
Sample: report.ready (fictional)
{
"id": "00000000-0000-4000-8000-0000000f0004",
"type": "report.ready",
"api_version": "2026-09-01",
"occurred_at": "2026-09-02T16:05:00.000Z",
"agency_id": "00000000-0000-4000-8000-00000000a9e1",
"data": {
"report": {
"id": "00000000-0000-4000-8000-0000000000e1",
"state": "ready",
"url": "https://www.recruit100x.com/reports/00000000-0000-4000-8000-0000000000e1",
"generated_at": "2026-09-02T15:22:00.000Z"
},
"role": {
"id": "00000000-0000-4000-8000-0000000000b1",
"title": "Senior FP&A Analyst",
"client_label": "Northwind Health"
},
"candidate": {
"id": "00000000-0000-4000-8000-0000000000c1",
"full_name": "Jordan Example",
"email": "jordan.example@example.com",
"phone": "+15555550123",
"anonymized": false
},
"screen": {
"completed_at": "2026-09-02T15:18:00.000Z",
"duration_seconds": 1080,
"channel": "voice",
"channel_reason": null
},
"facts": [
{
"id": "comp_expectation",
"label": "Compensation",
"status": "stated",
"value": "135 to 145 thousand base",
"confidence": "high",
"evidence": [
{
"quote": "I'm looking for 135 to 145 thousand base",
"t": 412
}
]
},
{
"id": "notice_period",
"label": "Notice period",
"status": "stated",
"value": "two weeks",
"confidence": "high",
"evidence": [
{
"quote": "I'd need to give two weeks",
"t": 498
}
]
},
{
"id": "work_authorization",
"label": "Work authorization",
"status": "stated",
"value": "authorized, no sponsorship needed",
"confidence": "medium",
"evidence": [
{
"quote": "I'm authorized to work here and don't need sponsorship",
"t": 530
}
]
},
{
"id": "location",
"label": "Location",
"status": "not_stated",
"value": null,
"confidence": null,
"evidence": []
},
{
"id": "licensure",
"label": "License / certification",
"status": "not_asked",
"value": null,
"confidence": null,
"evidence": []
}
],
"knockouts": [
{
"id": "ko-1-work_authorization",
"label": "Work authorization",
"outcome": "pass",
"quote": "I'm authorized to work here and don't need sponsorship",
"t": 530
}
],
"dimensions": [
{
"id": "forecasting",
"label": "Forecasting and planning",
"band": "strong",
"evidence": [
{
"quote": "I rebuilt the rolling forecast so it refreshed weekly from the ledger",
"t": 731
},
{
"quote": "we cut the variance to under two percent",
"t": 790
}
]
},
{
"id": "communication",
"label": "Communication",
"band": "meets",
"evidence": [
{
"quote": "I walk the budget owners through it every Monday",
"t": 845
}
]
},
{
"id": "systems",
"label": "Planning systems",
"band": null,
"evidence": []
}
],
"flags": [
{
"kind": "answer_length_anomaly",
"explanation": "One answer was much longer than the others. This can be wrong and never affects ranking."
}
],
"summary": {
"verdict": "Clear forecasting depth with specific examples; systems experience was not covered.",
"strengths": [
"Rebuilt a weekly rolling forecast",
"Explains numbers to budget owners"
],
"concerns": [
"Planning systems not discussed"
],
"suggested_follow_ups": [
"Ask which planning tools they have used"
]
},
"decision": {
"value": "advance",
"note": "Strong forecasting; send to client.",
"decided_by": "recruiter@agency.example",
"decided_at": "2026-09-02T16:05:00.000Z"
},
"submittal_note": {
"status": "approved",
"text": "Jordan rebuilt a weekly rolling forecast and is looking for 135 to 145 thousand base with two weeks' notice."
},
"ats_note_text": "Recruit100x screening report: Jordan Example\nRole: Senior FP&A Analyst (client: Northwind Health)\nScreened: 2026-09-02, voice interview, 18 min\nDecision: Advanced by recruiter@agency.example on 2026-09-02\nDecision note: Strong forecasting; send to client.\n\nFACTS\n- Compensation: 135 to 145 thousand base\n- Notice period: two weeks\n- Work authorization: authorized, no sponsorship needed\n- Location: not assessed\n- Reason for looking: not assessed\n- Other processes: not assessed\n- License / certification: not assessed\n\nMUST-HAVES\n- Work authorization: Meets — \"I'm authorized to work here and don't need sponsorship\" [08:50]\n\nASSESSMENT\n- Forecasting and planning: Strong evidence — \"I rebuilt the rolling forecast so it refreshed weekly from the ledger\" [12:11]\n- Communication: Meets expectation — \"I walk the budget owners through it every Monday\" [14:05]\n- Planning systems: Not observed\n\nSTRENGTHS\n- Rebuilt a weekly rolling forecast\n- Explains numbers to budget owners\n\nCONCERNS\n- Planning systems not discussed\n\nFull report: https://www.recruit100x.com/reports/00000000-0000-4000-8000-0000000000e1",
"verification": {
"status": "verified"
},
"billable": true
}
}Sample: invite.sent (fictional)
{
"id": "00000000-0000-4000-8000-0000000f0001",
"type": "invite.sent",
"api_version": "2026-09-01",
"occurred_at": "2026-09-02T16:05:00.000Z",
"agency_id": "00000000-0000-4000-8000-00000000a9e1",
"data": {
"invite": {
"id": "00000000-0000-4000-8000-0000000000d1",
"status": "sent",
"sent_at": "2026-09-01T14:00:00.000Z",
"opened_at": null,
"expires_at": "2026-09-08T23:59:59.999Z",
"opened_via": null
},
"candidate": {
"id": "00000000-0000-4000-8000-0000000000c1",
"full_name": "Jordan Example",
"email": "jordan.example@example.com",
"phone": "+15555550123",
"anonymized": false
},
"role": {
"id": "00000000-0000-4000-8000-0000000000b1",
"title": "Senior FP&A Analyst",
"client_label": "Northwind Health"
}
}
}Checking the signature
Compute an HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body} with the base64-decoded part of your whsec_ secret, base64-encode it and compare it with each space-separated v1, value in webhook-signature. While a secret is being rotated, the header carries two values (new and old) for 24 hours. Use the raw body exactly as received, before any JSON parsing.
Node.js
const crypto = require("node:crypto");
// secret: the whsec_… value shown once when you created the endpoint.
// headers: the request headers (lower-case names). rawBody: the body exactly as received.
function verifyRecruit100xWebhook(secret, headers, rawBody) {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatures = headers["webhook-signature"] || "";
if (!id || !timestamp) return false;
// Refuse messages older or newer than 5 minutes (replay protection).
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = "v1," + crypto
.createHmac("sha256", key)
.update(id + "." + timestamp + "." + rawBody)
.digest("base64");
// During a secret rotation the header carries two values; either may match.
return signatures.split(" ").some((candidate) =>
candidate.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(candidate), Buffer.from(expected)));
}
module.exports = { verifyRecruit100xWebhook };
Python 3.9+
import base64, hashlib, hmac, time
# secret: the whsec_... value shown once when you created the endpoint.
# headers: a dict of request headers (lower-case names). raw_body: the body bytes as received.
def verify_recruit100x_webhook(secret, headers, raw_body):
msg_id = headers.get("webhook-id")
timestamp = headers.get("webhook-timestamp")
signatures = headers.get("webhook-signature", "")
if not msg_id or not timestamp:
return False
# Refuse messages older or newer than 5 minutes (replay protection).
if abs(time.time() - int(timestamp)) > 300:
return False
key = base64.b64decode(secret.removeprefix("whsec_"))
signed = f"{msg_id}.{timestamp}.".encode() + raw_body
expected = "v1," + base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
# During a secret rotation the header carries two values; either may match.
return any(hmac.compare_digest(candidate, expected) for candidate in signatures.split(" "))
API reference
Authentication. Send Authorization: Bearer <key> over HTTPS to your Recruit100x address. A missing, revoked or expired key gets 401; a key without the needed permission gets 403. When an operator has turned the API off, calls get 503.
Permissions.
read:reports— Report details, including candidate contact details and quotes.read:roles— Your roles and their invitation counts.write:invites— Add candidates and send them interview invitations (uses credits when they finish).manage:hooks— Let Zapier or Make subscribe to events.
Limits. 60 requests a minute per key. Over the limit you get 429 with a Retry-After header in seconds.
Errors. Every error is JSON: {"error": {"code": "…", "message": "…", "details"?: …}}.
Pagination. List calls take limit (default 25, at most 100) and return next_cursor; pass it back as cursor until it is null.
| Route | Permission | What it does |
|---|---|---|
GET /api/v1/me | any | The agency and key you are connected as (use it to test a connection). |
GET /api/v1/roles?status=active | read:roles | Roles with invitation counts. |
GET /api/v1/roles/{id}/reports?state=ready&since=&limit=&cursor= | read:reports | Report summaries for a role, newest first. |
GET /api/v1/reports/{id} | read:reports | One full report (the same object as the report.ready webhook). |
POST /api/v1/roles/{id}/invites | write:invites | Add up to 100 candidates ({full_name, email, phone?, source?}) and send invitations; optional sms_consent_attested. |
POST /api/v1/hooks | manage:hooks | Subscribe a URL to events ({url, events[], source?}); returns the signing secret once. |
DELETE /api/v1/hooks/{id} | manage:hooks | Unsubscribe. |
GET /api/v1/hooks/samples/{event} | the event's read scope | A sample payload for an event (fictional data). |
Candidate data and compliance
Each candidate record shows their consent history and data rights: export the record, start deletion (7-day grace), or place a legal hold (owners). Retention, notice templates and the audit log are under Settings → Hiring compliance.
See the compliance overview for what stays your responsibility by jurisdiction.
Still stuck?
Email support@recruit100x.com with your agency name and, if it is about a specific candidate or report, the link to it. We aim to answer within two business days.