Skip to content

Salesforce integration · Apex callout + Named Credential

Parse resumes and score candidates in Salesforce

Salesforce has no applicant tracking or resume parsing out of the box, so candidates usually live in Contacts, Leads or custom objects. An Apex job sends each uploaded CV to HireLayer through a Named Credential and writes the parsed fields, skills and score back to the record.

Salesforce side
Apex Queueable with callouts
Credentials
Named Credential sends X-API-Key
Callout timeout
120 s (the default is 10 s)
Cost
1 credit per resume, +1 per score
Salesforce + HireLayer
  1. 1A CV is uploadedSalesforceA recruiter adds a CV as a File on a Contact. A trigger on ContentDocumentLink, or a record-triggered flow on its asynchronous path, enqueues a Queueable job.
  2. 2Parse the resumeHireLayerThe job sends the file’s VersionData to HireLayer CV Extract through the Named Credential and gets contact details, experience, education, languages and skills.
  3. 3Score against a jobHireLayerFor a candidate linked to an open role, HireLayer Match compares the resume text with the job’s criteria and returns a score from 0 to 1 with an explanation.
  4. 4Update the recordSalesforceApex writes the title, phone, city, skills and score to the Contact, and can save a report as a File linked to it with FirstPublishLocationId.

Use cases

What recruiting teams do with HireLayer and Salesforce

  • Create candidates from CVs

    Recruiters attach a CV to a Contact and the Queueable fills its title, phone, city and skills, without retyping. The same call returns the name and email for new records.

  • Score candidates for open roles

    Store the criteria of each job on your own Job or Position object, then score every linked candidate and keep the score and sumary on the record for list views and reports.

  • Rank a shortlist

    Send up to 10 candidates’ resume texts with a job description to HireLayer Rank and get them back in order, each with a rationnale.

  • Search by skill

    Write normalized skills as Topics on the Contact, so recruiters find every candidate with a skil, whatever wording the CV used.

Setup

Connect Salesforce to HireLayer

Everything lives in your own org and is set up by a Salesforce admin or developer. No AppExchange package is involved.

  1. 1

    Store the API key in a Named Credential

    Create a Named Credential called HireLayer for https://hirelayer.co, with an External Credential that sends your HireLayer API key in the X-API-Key header. Apex then calls callout:HireLayer/… and never handles the key.

  2. 2

    Add the fields

    Add custom fields to Contact for what has no standard home, such as Skills__c (long text) and a score. Use child objects if you want work experience and education as separate records.

  3. 3

    Enqueue on upload

    An after-insert trigger on ContentDocumentLink, filtered to links whose LinkedEntityId is a Contact, calls System.enqueueJob with the Contact and document IDs. Callouts are not allowed while a record is being saved, hence the asynchronous job.

  4. 4

    Parse, then write back

    The Queueable makes its callouts first and its DML after, since Apex refuses a callout once the transaction has uncommitted work. Optionally score with Match and save the report as a File.

Field mapping

Where HireLayer results go in Salesforce

Salesforce has no candidate object by default. This recipe writes to Contact; the same approach works on Lead or your own Candidate object.

HireLayer fieldSalesforce (Contact)Note
info_candidate.first_name, last_nameFirstName, LastName
info_candidate.email, phone_numberEmail, MobilePhonePhone in E.164 format
info_candidate.job_titleTitle
info_candidate.location.cityMailingCity
skills[].skill_titleSkills__c (custom long text) or TopicsNo standard skills field
work_experiences[], educations[]Custom child objectsFor example Work_Experience__c, Education__c
score + summaryCustom fields, or a File (ContentVersion with FirstPublishLocationId)

Example

An Apex Queueable that parses the CV

It reads the latest version of the uploaded file, sends it as multipart form data through the HireLayer Named Credential, and updates the Contact. It overwrites the fields it sets: add your own rules to keep values recruiters entered.

HireLayerParseResume.clsapex
public class HireLayerParseResume implements Queueable, Database.AllowsCallouts {
    public class HireLayerException extends Exception {}
    private final Id contactId;
    private final Id documentId;

    public HireLayerParseResume(Id contactId, Id documentId) {
        this.contactId = contactId;
        this.documentId = documentId;
    }

    public void execute(QueueableContext context) {
        ContentVersion cv = [
            SELECT PathOnClient, VersionData FROM ContentVersion
            WHERE ContentDocumentId = :documentId AND IsLatest = true
        ];

        // multipart/form-data body with one "file" part
        String boundary = 'HireLayer' + Datetime.now().getTime();
        String head = '--' + boundary + '\r\nContent-Disposition: form-data; name="file"; filename="'
            + cv.PathOnClient + '"\r\nContent-Type: application/octet-stream\r\n\r\n';
        String tail = '\r\n--' + boundary + '--\r\n';
        Blob body = EncodingUtil.convertFromHex(
            EncodingUtil.convertToHex(Blob.valueOf(head))
            + EncodingUtil.convertToHex(cv.VersionData)
            + EncodingUtil.convertToHex(Blob.valueOf(tail)));

        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:HireLayer/api/v3/parser'); // adds X-API-Key
        req.setMethod('POST');
        req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
        req.setBodyAsBlob(body);
        req.setTimeout(120000); // default is 10 s; parsing takes about 35 s
        HttpResponse res = new Http().send(req);
        if (res.getStatusCode() != 200) {
            throw new HireLayerException('HireLayer returned ' + res.getStatusCode());
        }

        Map<String, Object> parsed = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
        Map<String, Object> info = (Map<String, Object>) parsed.get('info_candidate');
        Map<String, Object> location = (Map<String, Object>) info.get('location');
        List<String> skills = new List<String>();
        for (Object item : (List<Object>) parsed.get('skills')) {
            skills.add((String) ((Map<String, Object>) item).get('skill_title'));
        }

        // DML after the callout: Apex refuses callouts after uncommitted work
        update new Contact(
            Id = contactId,
            Title = (String) info.get('job_title'),
            MobilePhone = (String) info.get('phone_number'), // E.164
            MailingCity = location == null ? null : (String) location.get('city'),
            Skills__c = String.join(skills, ', ') // custom long text field
        );
    }
}

Limits

Good to know

  • Not an AppExchange app

    HireLayer has no AppExchange listing or managed package. The Apex class and Named Credential live in your org, or ask us to build the connector with your team.

  • Callout limits

    Apex allows 120 seconds of callouts per transaction, and 12 MB per request in asynchronous Apex, counted toward the 25 MB heap. Parsing takes about 35 seconds; for the rare file that takes longer, retry or use HireLayer’s async mode with a webhook_url you host.

  • Flow covers the JSON endpoints

    Flow’s HTTP Callout action can call HireLayer’s JSON endpoints, such as matching and ranking. Sending a file as multipart form data is not documented for it, so resume parsing goes through Apex.

  • Results written in French

    Criteria labels, match summaries and rationales are in French; scores and field names are not. HireLayer processes data in the EU, and do_not_store_data keeps no copy of the file.

FAQ

HireLayer and Salesforce: questions

Is there a HireLayer app on Salesforce AppExchange?

No. HireLayer connects through Apex and a Named Credential in your own org, as shown on this page. We can build the connector with your Salesforce team on request.

Does Salesforce have a built-in resume parser?

Not in core Salesforce, which has no applicant tracking object either. CVs are usually stored as Files on a Contact, Lead or custom object, and a parser like HireLayer fills the fields.

Can I do this with Flow, without Apex?

Partly. Flow’s HTTP Callout action works with HireLayer’s JSON endpoints: job criteria, matching with resume text, ranking and skills. Parsing a file needs a multipart upload, so it uses a short Apex class that an invocable action can enqueue from a flow.

Why does my callout time out after 10 seconds?

That is Apex’s default callout timeout. Set req.setTimeout(120000), the maximum, and run the callout in a Queueable or future method: parsing takes about 35 seconds.

I use a recruiting app built on Salesforce. Does this work?

Yes. Packages such as Bullhorn for Salesforce keep candidates in their own objects with namespaced fields: point the update at those fields instead of Contact, and check how the package parses resumes first.

Connect Salesforce to HireLayer today

The Free plan includes 50 credits a month, no card required. One successful call is one credit, on every API.