ResumeParser.pro

Parse Resumes in PHP and Laravel

Two official Composer packages, one for parsing and one for match scoring, plus a raw Guzzle fallback for framework-free PHP. Working code for all three, nothing hypothetical.

To parse a resume in Laravel, install sharpapi/laravel-resume-parser, set SHARP_API_KEY in your .env, and call ResumeParserService::parseResume(). The service returns a status URL; fetchResults() polls it and hands you the structured candidate data.

Laravel — the parser package

composer require sharpapi/laravel-resume-parser
use SharpAPI\ResumeParser\ResumeParserService;

class ImportResumeController extends Controller
{
    public function __construct(private ResumeParserService $resumeParser) {}

    public function store(Request $request)
    {
        $path = $request->file('resume')->getRealPath();

        $statusUrl = $this->resumeParser->parseResume($path, 'English');

        $result = $this->resumeParser->fetchResults($statusUrl);

        return response()->json($result->getResultJson());
    }
}

fetchResults() handles the polling loop internally — each job typically finishes in a few seconds. For upload-heavy apps, move the two calls into a queued job so the HTTP request returns instantly.

Laravel — match scoring, same pattern

The sibling package sharpapi/laravel-resume-job-match-score scores the parsed candidate against a job description — including the context directives that tune the weighting:

composer require sharpapi/laravel-resume-job-match-score
use SharpAPI\ResumeMatchScore\ResumeMatchScoreService;

$service = new ResumeMatchScoreService();

$context = "EMPHASIZE: backend scalability\n"
    ."DEEMPHASIZE: frontend frameworks\n"
    ."CREDIT: AWS";

$statusUrl = $service->matchResumeToJob(
    storage_path('resumes/candidate.pdf'),
    'We are hiring a Senior Backend Developer (PHP/Laravel)…',
    'English',
    $context,
);

$scores = $service->fetchResults($statusUrl)->toArray();
// $scores['match_scores']['overall_match'] → 0–100

Plain PHP — no framework, no package

The endpoint is ordinary multipart REST, so Guzzle alone covers it:

Guzzle — framework-free
$client = new \GuzzleHttp\Client();

$submit = $client->post('https://sharpapi.com/api/v1/hr/parse_resume', [
    'headers' => ['Authorization' => 'Bearer '.$apiKey],
    'multipart' => [
        ['name' => 'file', 'contents' => fopen('candidate.pdf', 'r')],
        ['name' => 'language', 'contents' => 'English'],
    ],
]);

$statusUrl = json_decode((string) $submit->getBody(), true)['status_url'];

do {
    sleep(2);
    $job = json_decode((string) $client->get($statusUrl, [
        'headers' => ['Authorization' => 'Bearer '.$apiKey],
    ])->getBody(), true);
} while ($job['data']['attributes']['status'] === 'pending');

$candidate = $job['data']['attributes']['result'];

Where to take it

The full response schema is explorable at resume to JSON; the field reference lists all 50+ fields for your migrations. Parsing a legacy database of CVs? The bulk parsing guide covers queues, webhooks and cost estimation for Laravel specifically.

Questions, answered

Is there an official Laravel package?

Yes — composer require sharpapi/laravel-resume-parser. Set SHARP_API_KEY in .env, inject ResumeParserService, and call parseResume($path, $language). A sibling package covers job match scoring.

Can I use plain PHP without Laravel?

Yes — the endpoint is standard multipart REST, so Guzzle or curl works directly. The Laravel package just removes the boilerplate: auth header, multipart encoding and the polling loop.

How should I parse thousands of resumes in Laravel?

Dispatch one queued job per file and let each submit to the API and register a webhook. The API side is async by design, so your queue concurrency is the only throttle. Details in the bulk parsing guide.