Lever
This page covers integrating Incode identity verification into the Lever Applicant Tracking System (ATS). This integration uses Tines, a powerful automation platform, to orchestrate the verification flow between Lever and Incode. When a candidate reaches a designated hiring stage, Tines sends them a personalized verification link, captures the result, and writes it back to their Lever opportunity automatically.
This integration handles the full candidate verification lifecycle. It:
- Validates incoming Lever webhook signatures using HMAC-SHA256.
- Triggers only when a candidate reaches your designated verification stage.
- Fetches candidate details from Lever, generates an Incode verification link, and emails it to the candidate.
- Stores a trace record in Tines to map verification results back to the correct Lever opportunity.
- Listens for Incode verification status updates and writes results, including notes and tags, back to Lever automatically.
NoteYou will need an active Tines workspace, a Lever account with API access, and an Incode account with API credentials to proceed.
Prerequisites
Ensure you have the following before you begin:
| Requirement | Details |
|---|---|
| Tines | An active workspace with permission to create stories, credentials, and records. The Records feature must be enabled. |
| Lever ATS | An account with Admin or Super Admin access to create API keys and configure webhooks. |
| Incode | An active integration with integration ID, secret, and x-api-key available. |
| Email sending | Tines email delivery is used to send verification links. Ensure your workspace domain is allowlisted for outbound email. |
Understand Flows
The automation runs as two independent flows that communicate through a shared Tines Records table.
Flow 1: Trigger and Send Verification
Fires when a candidate moves to the verification stage in Lever.
[Stage change webhook] → [Validate signature] → [Check stage ID]
↓
[GET /candidates/{id}] → [Extract name & email] → [3 min delay]
↓
[GET Incode auth token] → [Generate verification link]
↓
[Capture Tines record] → [Send email to candidate]
Flow 2: Receive Result and Update Lever
Fires when Incode posts a verification status event to your Tines webhook.
[Status update webhook] → [Check event_type == succeeded]
↓
[Match trace ID → OpportunityID]
↓
[Add tag: biometric-verified] → [Post verification note]
WarningFlow 2 triggers only on
verification.succeededevents. Failed or expired verifications are written as notes to Lever but do not trigger the tag update. You can extend the story to handle additional event types such asverification.failed.
Set Up the Lever Integration
Configure Credentials
This Tines story requires five credentials stored in your Tines workspace. Go to Credentials in the Tines sidebar and create each one as a Text credential.
| Credential name | Source | Description |
|---|---|---|
lever_api_key | Lever > Settings > Integrations > API Credentials | Your Lever API key. Used as a Bearer token to fetch candidate data, post notes, and add tags. |
incode_x_api_key | Dashboard > API Keys | The x-api-key header value for Incode's authorization endpoint. |
incode_workforce_integrationid | Dashboard > Integrations | The unique identifier for your Incode integration. |
incode_workforce_secret | Dashboard > Integrations | The secret for your integration, used for server-side token generation. |
tines_api_key_lever_incode_records | Tines > Your Profile > API Keys | A Tines API key used by the story to query its own Records table when matching a trace ID to an opportunity. |
WarningCredential names must match exactly as shown. The story references them using
CREDENTIAL.NAMEsyntax. A typo will cause silent authentication failures.
Set Up the Lever Webhook
Lever must send a webhook event whenever a candidate's pipeline stage changes.
- Copy the Tines webhook URL: After importing the story, open the
lever_webhookagent and copy the generated webhook URL:https://<your-tenant>.tines.com/webhook/<story-guid>/871aa415a5da64cdfa3fba63527c374b - Create the webhook in Lever: In Lever, go to Settings > Integrations > Webhooks and add a new webhook:
Field Value URL Your Tines webhook URL from above Events candidateStageChangeSigning token Copy this value—you'll need it in the next step - Update the HMAC signature secret in the story: Open the
validate_webhook_signatureagent in Tines and replace the placeholder signing token with your Lever webhook signing token:{ "calculated_signature_raw": "<<HMAC_SHA256(LOCAL.concatened, \"YOUR_LEVER_SIGNING_TOKEN_HERE\")>>" }
WarningThe story ships with a placeholder signing token. Replace it with your Lever signing token or the signature check will reject all incoming webhooks.
Set Up the Incode Webhook
Incode must POST verification status events to a second Tines webhook endpoint. This drives Flow 2.
- Copy the verification status webhook URL: After importing the story, open the
Get_verification_status_updatesagent and copy its webhook URL:https://<your-tenant>.tines.com/webhook/<story-guid>/59ab814228451619d85618e952e62c34 - Register the webhook in Incode: In Dashboard, go to Configuration > Webhooks and configure a webhook pointing to the URL above. The story expects the following fields in the webhook payload:
{ "event_type": "verification.succeeded", "data": { "verification_trace_id": "<trace-id>", "failure_reason": "<status message>", "ip": "<candidate IP>", "user_name": "<candidate name>", "latitude": 0.0, "longitude": 0.0 } }
Configure Your Lever Stage ID
The story triggers only when a candidate advances to a specific Lever pipeline stage. You must update the stage ID to match a stage in your own Lever environment.
- Find the stage ID in Lever: Use the Lever API to list your pipeline stages:
Each stage has an
curl -X GET https://api.lever.co/v1/stages \ -H "Authorization: Bearer <your-lever-api-key>"idfield. Copy the ID for your target stage: for example, Background Check or Offer. - Update the
validate_stageagent: Open thevalidate_stageagent in Tines and replace the stage ID in the trigger rule:{ "type": "field==value", "value": "YOUR-STAGE-UUID-HERE", "path": "EXTRACT_DATA.TO_STAGE_ID" }
NoteThe story ships with a sample stage ID (
73f73269-c81e-465f-bdf4-25c76929d60a) that does not match your environment. If you don't update it, the story receives all stage change events but never proceeds past thevalidate_stagetrigger.
Import the Tines Story
- Download the story file: Download
lever-incode-candidate-biometric-identity-verification.jsonfrom your Incode account manager. - Import into Tines: In your Tines workspace, click New Story > Import and upload the JSON file. Tines then creates all agents, connections, and the Tines Records table automatically.
- Complete configuration: Before enabling the story, confirm the following:
- All five credentials are created in Tines.
- Lever webhook is configured to POST to
lever_webhook. - Lever HMAC signing token is updated in
validate_webhook_signature. - Stage ID is updated in
validate_stage. - Incode webhook is configured to POST to
Get_verification_status_updates. - Email sender name and reply-to address is updated in the Send Email Action.
- Redirect URL in
incode_verificationis updated to your domain.
- Enable and test: Enable the story in Tines. Move a test candidate to your verification stage in Lever and confirm the story fires, the email is sent, and a record appears in the Tines Records table.
Automation Agents Reference
The story contains 16 agents across both flows.
Flow 1: Send Verification
| Agent | Type | Description |
|---|---|---|
lever_webhook | WebhookAgent | Receives all candidateStageChange POST events from Lever. Responds with HTTP 200 immediately. |
validate_webhook_signature | EventTransformationAgent | Computes HMAC-SHA256 of token and triggeredAt using your Lever signing secret and compares it to the received signature. |
check_signature | TriggerAgent | Gate: passes only events where the computed signature matches the received signature. Rejects forged or replayed webhooks. |
extract_data | EventTransformationAgent | Extracts candidateId, opportunityId, fromStageId, toStageId, and stageName from the webhook payload. |
validate_stage | TriggerAgent | Gate: passes only events where toStageId equals your configured verification stage ID. |
get_candidate_details | HTTPRequestAgent | Calls GET /v1/candidates/{id} on the Lever API to retrieve the candidate's profile. |
extract_candidate_details | EventTransformationAgent | Parses name, email, and phone from the Lever response. Splits full name into first_name and last_name for Incode. |
Delay sending identity verification message | EventTransformationAgent (delay) | Waits 3 minutes before continuing. Allows stage transitions to settle in Lever before sending the email. |
get_incode_token | HTTPRequestAgent | Calls the Incode server-side authorization endpoint to obtain a short-lived session token using your integration credentials. |
incode_verification | HTTPRequestAgent | Generates a personalized, time-limited verification link for the candidate. The link is valid for 72 hours. |
Capture Record | RecordAgent | Creates a record in the Lever_Incode_Information table storing the opportunity ID, candidate ID, and Incode trace ID. |
Send Email Action | EmailAgent | Sends an HTML-formatted email to the candidate with the verification link and instructions. |
Flow 2: Receive Result
| Agent | Type | Description |
|---|---|---|
Get_verification_status_updates | WebhookAgent | Receives POST callbacks from Incode containing verification results. Second entry point of the story. |
Trigger Action | TriggerAgent | Gate: passes only events where event_type == "verification.succeeded". |
Match_record_trace_opportunity | HTTPRequestAgent | Queries the Tines Records API to find the opportunity ID matching the verification_trace_id from the Incode callback. |
update_lever_tag | HTTPRequestAgent | Calls POST /v1/opportunities/{id}/addTags to add the biometric-verified tag to the candidate's Lever opportunity. |
update_lever_note | HTTPRequestAgent | Posts a structured note to the Lever opportunity with the event type, status, trace ID, IP, name, and geolocation from the Incode verification result. |
API Reference
Incode APIs
Get Auth Token
POST https://demo-api-incode-id.incodesmile.com/v1/integration/authorize/server
x-api-key: CREDENTIAL.INCODE_X_API_KEY
Request body:
{
"integrationId": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
"secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET"
}Response:
{ "token": "<session-token>" }The token value is passed as the x-auth-token header in all subsequent Incode API calls.
Generate Verification Link
POST https://demo-api-incodesmile.com/v1/workforce/verification/candidate/generate-verification-link
x-auth-token: GET_INCODE_TOKEN.BODY.TOKEN
Request body:
{
"integrationID": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
"secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET",
"loginHint": "[email protected]",
"loginHintType": "EMAIL",
"validityMinutes": 4320,
"redirectUrl": "https://your-domain.com",
"givenNames": "First",
"lastName": "Last"
}Key response fields:
{
"verificationLink": "https://...",
"verificationTraceId": "..."
}Lever APIs
Get Candidate Details
GET https://api.lever.co/v1/candidates/{candidateId}
Authorization: Bearer CREDENTIAL.LEVER_API_KEY
Key response fields used:
data.name // full name — split into first/last
data.emails[0] // primary email address
data.phones[0] // primary phone number
Add Tag to Opportunity
POST https://api.lever.co/v1/opportunities/{opportunityId}/addTags
Authorization: Bearer CREDENTIAL.LEVER_API_KEY
{ "tags": ["biometric-verified"] }Post Verification Note
POST https://api.lever.co/v1/opportunities/{opportunityId}/notes
Authorization: Bearer CREDENTIAL.LEVER_API_KEY
{
"secret": false,
"value": "Biometric Verification Update\n\nEvent: <event_type>\n\nVerification Details:\n- Status: ...\n- Trace ID: ...\n- IP: ...\n- Name: ...\n- Location: lat, lon\n\nProcessed: <timestamp>"
}Email Template
The Send Email Action agent sends an HTML email to the candidate with a personalized greeting, a verification button, and step-by-step instructions.
To customize the template, open the Send Email Action agent in Tines and update the following:
| Field | Default | Description |
|---|---|---|
sender_name | GoodLeap Talent Team | Your company's talent team name |
reply_to | [email protected] | Your recruitment team's reply-to email address |
subject | Identity Verification Request | Add your company name if needed |
| CTA button color | #00AEEF | Your brand's primary color |
| Contact email in body | [email protected] | Your recruitment team's email address |
redirectUrl in incode_verification | https://goodleap.com | Your company website or careers page URL |
Tines Records Schema
The story creates and queries a Records table called Lever_Incode_Information. This table connects Flow 1 (send verification) and Flow 2 (receive result).
| Field | Type | Description |
|---|---|---|
| Story name | TEXT | Name of the Tines story that created the record. For debugging. |
| Timestamp | TIMESTAMP | Date and time the record was created. |
| OpportunityID | TEXT | The Lever opportunity ID. Used when writing back notes and tags in Flow 2. |
| CandidateID | TEXT | The Lever candidate ID. Stored for reference and audit. |
| TraceID | TEXT | The Incode verificationTraceId. Used as the lookup key in Flow 2 to match the callback to the original opportunity. |
| Updated at | TIMESTAMP | Auto-populated timestamp for when the record was last modified. |
NoteThe
Match_record_trace_opportunityagent queries this table using the Tines Records API athttps://<your-tenant>.tines.com/api/v1/records, filtering by TraceID to find the corresponding Lever OpportunityID. Ensuretines_api_key_lever_incode_recordshas permission to read this table.
Troubleshooting
Story Fires but No Email Is Sent
Check the following in order:
check_signaturetrigger not passing: Verify your HMAC signing token invalidate_webhook_signaturematches the signing token shown in Lever's webhook settings exactly.validate_stagetrigger not passing: Verify the stage ID in the trigger rule matches the UUID of your target pipeline stage in Lever.get_incode_tokenreturning non-200: Check yourincode_x_api_key,incode_workforce_integrationid, andincode_workforce_secretcredentials in Tines.
Lever Note or Tag Not Written After Verification
Confirm the following:
- The Incode webhook is correctly configured to POST to the
Get_verification_status_updatesURL. - The
event_typefrom Incode is exactlyverification.succeeded: the Trigger Action performs a strict string match. - A Tines record exists for the
verification_trace_id. Check the Records table to confirm Flow 1 ran successfully for that candidate. tines_api_key_lever_incode_recordsis valid and has read access to theLever_Incode_Informationrecords table.
Signature Validation Fails for All Events
The HMAC signing token in validate_webhook_signature must match your Lever webhook's signing token exactly.
- Go to Lever > Settings > Integrations > Webhooks.
- Click your webhook.
- Copy the signing token.
- Paste the signing token into the
HMAC_SHA256expression in the Tines agent, replacing any placeholder value.
Incode API Returns 401
Your incode_x_api_key, incode_workforce_integrationid, or incode_workforce_secret credentials are incorrect or expired. Verify them in the Incode Dashboard and re-create the Tines credentials.
TipUse Tines' built-in event log for each agent to inspect the exact payload received and response. This is the fastest way to identify where an issue occurs.
