InHire
The InHire integration is stage-driven. When a recruiter moves a candidate (talent) into a stage you configured, Deeper Signals invites them to the assessments of a campaign cloned per job. When they finish, the PDF reports are uploaded to the candidacy, a comment and feedback entry are added and the candidacy is tagged Assessment Completed.
How it works
- Deeper Signals signs in to InHire with a service user you provide, and registers one webhook, Deeper Signals stage trigger, for the
JOB_TALENT_STAGE_ADDEDevent. - You choose a template campaign (a hiring campaign with the assessments, reports and settings) and the stage names that trigger an invitation, optionally restricted to specific jobs.
- On a matching stage change, Deeper Signals reads the candidacy and the talent, finds or creates the campaign InHire - <job name> (cloned from the template), finds or creates the candidate by e-mail and sends the invitation.
- On completion the reports are written back to the candidacy. The candidate's stage is not changed and no numeric score is written to InHire; recruiters open the Deeper Signals profile link in the comment for details.
Prerequisites
| Where | What |
|---|---|
| InHire | Your tenant id, and the e-mail and password of an InHire user allowed to manage webhooks, jobs and talents. The password is used once to sign in and is not stored. |
| InHire | A pipeline stage (per job or shared) that recruiters will use to trigger the assessment, for example Deeper Signals. |
| Deeper Signals | An account administrator; API access enabled on the account by Deeper Signals. |
The webhook is registered by Deeper Signals; nothing has to be configured manually in InHire.
Setup
- Connect. In the admin app open Settings → Integrations → InHire and enter the tenant, e-mail and password. (API:
POST /admin/integrations/inhire/{account}/createwith{"tenant", "email", "password"}.) - Configure. Pick the template campaign and the trigger stages. The integration starts in dry run with write-back off, so you can watch events arrive before any candidate is invited. (API:
POST /admin/integrations/inhire/{atsIntegration}/configurewith{"templateCampaignId": 17, "stages": [{"stageName": "Deeper Signals", "jobId": null}], "dryRun": true, "writeback": false}.) - Test. Run the connection test; it also re-activates the integration after an outage. (API:
GET /admin/integrations/inhire/{atsIntegration}/test→{"valid", "active"}.) - Go live. Switch dry run off and write-back on in the same configure call.
- Reports. Under Report mapping choose which PDFs are uploaded per assessment.
If the InHire password changes, use Reconnect (POST .../reconnect, same body as create; the tenant must match). Changing the tenant requires a new integration.
The integration view (GET /admin/integrations/inhire/{atsIntegration}) shows the configuration, whether tokens are present, the registered webhook, the last event, the last error and a health block. Secrets are never returned.
Runtime contract
Inbound: POST /integration/webhook/inhire/{webhookToken}. The random token in the path identifies the integration; the body must be JSON of at most 64 KiB.
| Field | Required | Use |
|---|---|---|
tenantId, jobId, talentId, stageName | yes | Identify the event. Stage names are matched exactly, case-insensitively. |
jobName, source, createdAt, stageOriginId | no | Kept as event metadata; jobName names the per-job campaign. |
{
"tenantId": "acme", "jobId": "job-1", "jobName": "Data Analyst",
"previousStageName": "Applied", "stageName": "Deeper Signals", "stageType": "SCREENING",
"talentId": "talent-1", "createdAt": "2026-10-01T12:00:00+00:00"
}
Responses: 200 {"processed": false, "reason": "queued"} once the event is stored for processing; 400 for invalid JSON or missing fields (missing: [...]); 413 for an oversized body; 200 with reason: tenant_mismatch for another tenant. Processing happens asynchronously, so a 200 means accepted, not invited.
Outbound (every call carries X-Tenant and a bearer token; at most 5 requests per second): GET job-talents/{jobId}/talents/{talentId}, signed file upload (POST files/signature, category job-talent-general-files), PATCH job-talents/talents/{jobTalentId} with the new files, a stageChangeComment and a feedback entry reading Deeper Signals assessment completed. Profile: <URL>, and POST job-talents/talents/{id}/tags for Assessment Completed. Webhooks are managed through the InHire webhooks API.
Monitoring
- Delivery health runs every 15 minutes and stage health daily: they report configured stages missing in InHire and candidates in a trigger stage who have no Deeper Signals invitation yet. The result is the
healthblock of the integration view (healthy,attention_required,check_failed). - Processing reasons you may see on an event:
stage_not_configured,duplicate_event,missing_candidate_email,dry_run,integration_inactive. - Write-back states:
uploading,patching,tagging,succeeded; an ambiguous outcome is flagged for review rather than retried blindly, so a candidate never receives a second invitation e-mail by accident. - Expired InHire credentials show as InHire authentication expired; reconnect required.
Limitations
- Stage matching is by name (optionally per job); InHire's own webhook filters are only pushed when every configured stage shares the same name or job.
- The candidate must have an e-mail address on the talent record.
- Results are written back once all assessments of the campaign are complete; no score or stage change is written to InHire.
- One InHire integration per Deeper Signals account.