SpringVerify BGV API Integration Guide | REST API Documentation

SpringVerify BGV API — Integration Guide

Version 3.3 · Last updated 2026-09-24

This guide covers the REST API your system uses to create a candidate, submit their verification details, track progress, and download the final report. A Postman collection is available alongside this guide.


Overview — the core flow

Every integration follows five calls:

  1. GET /external/v1/candidate/packages — Read your company's configuration: packages, required fields, categories, tags, custom fields, and add-on catalogue.

  2. POST /external/v1/candidate/add — Create a candidate and receive a candidate_id.

  3. POST /external/v2/candidate/submit-bgv — Submit the candidate's check data.

  4. GET /external/v1/candidate/details — Track status and read per-check results.

  5. GET /external/v1/candidate/report/pdf — Download the completed report.

A few things apply to every endpoint:

  • Authentication is a bearer token that identifies your company — you never send a company id.
  • Requests and responses are JSON. The report can also be returned as a binary PDF or as base64.
  • Configuration is company- and environment-specific. Always read package identifiers, required fields, categories, tags, and custom fields live from GET /packages. Never hard-code them.
  • Polling is optional. Completion can be pushed via webhook instead.

Authentication

SpringVerify provisions your company with an API token. Send it on every request:

Authorization: Bearer <YOUR_API_TOKEN>
Content-Type: application/json

Keep the token secret; it is a long-lived credential. A missing or invalid token returns 401 Unauthorized.


Base URL and environments

  • Sandbox: https://api-acceptance-2-sa.in.springverify.com
  • Production: https://api-sa.in.springverify.com

Your API token belongs to one environment. Package ids, category ids, tag ids and custom fields also differ between sandbox and production — read GET /packages in each environment rather than reusing values.


1. GET /external/v1/candidate/packages

Returns your company's configuration. Call this first and cache the result. There are no request fields; the configuration is derived from the token.

Sample request:

curl --location 'https://api-acceptance-2-sa.in.springverify.com/external/v1/candidate/packages' \ --header 'Authorization: Bearer <YOUR_API_TOKEN>'

Key response fields:

  • required_fields — Candidate fields that POST /add rejects if missing (e.g. EMAIL, PHONE, EMPLOYEE_ID).
  • packages[].subtype_id — The value you pass to POST /add. It fully identifies the package.
  • packages[].config — What the package runs (identity, address, employment, education, court, etc.) and the counts validated at submit.
  • addons — Optional checks available per candidate with your negotiated price.
  • categories and tags — Company-defined labels for organising candidates.
  • credits — Your current credit balance.

2. POST /external/v1/candidate/add

Creates a candidate against a package and returns a candidate_id. The candidate lands in Awaiting Input.

Key request fields:

  • candidate.name (required) — Letters, spaces, dot, and hyphen only. Digits are rejected.
  • candidate.email / candidate.phone — Required if they appear in your required_fields.
  • candidate.invite (required) — false: you submit all data by API. true: the candidate fills the form (requires email).
  • package.subtype_id (required) — From GET /packages.
  • candidate.resume — Résumé as an https URL or a base64 object { content, content_type, name }. Max 20 MB.
  • addons — Extra checks for this candidate. Send keys in lowercase (e.g. employment, not EMPLOYMENT).
  • candidate.meta_data — Free-form JSON echoed back unchanged in GET /details and the webhook. Use it to carry your own reference.

Response: data.candidate_id — use this for submit and GET /details.

Status codes: 200 created · 400 validation / invalid subtype / insufficient credits · 409 duplicate candidate · 413 résumé too large.


3. POST /external/v2/candidate/submit-bgv

Submits the candidate's check data. On success, SpringVerify creates every check the package requires and moves the candidate out of Awaiting Input.

Checks are keyed objects: identity_1, employment_1, education_1, current / permanent for addresses. Each entry may carry a documents array of either hosted URLs or inline base64 files.

The payload is validated against a strict allow-list. An unknown key is rejected, not ignored. Nothing is written until the whole payload passes; a failed request leaves the candidate exactly as it was and you can correct and resend.

Key sections:

  • candidate_id (required)
  • basic_details — full_name, dob, gender, mobile_number, uan_number, etc.
  • identity — keyed identity_1, identity_2, ... Each has id_type (PAN / AADHAAR / PASSPORT / DL / VOTER_ID), id_number, name_on_document, documents[].
  • employment — keyed employment_1, etc. Includes company_name, designation, start_date / end_date, hr_info, manager_info, documents[].
  • education — keyed education_1, etc. Includes course_type, degree, university_name, documents[].
  • address — keyed current, permanent, other_1, etc. Do not send a type inside the entry — the type comes from the key. Latitude and longitude are strings.
  • social_media — linkedin_url, facebook_url, twitter_url, instagram_url.
  • consent — { "doc_url": "https://..." }. Without it, the candidate is held in Consent missing.

Status codes: 200 submitted · 400 validation failure (every problem listed in errors[]) · 409 already submitted.


4. GET /external/v1/candidate/details

Returns a candidate's status and per-check detail. Provide either a single identifier (candidate_id, candidate_uuid, or email) or limit and offset.

Useful query parameters:

  • include_check_status=1 — Include each check's check_status and check_status_code.
  • include_check_details=1 — Add per-check date fields and verifier comments.
  • include_check_remarks=1 — Add the insufficiency note (requires company setting enabled).
  • include_documents_url=1 — Add pre-signed download links for each document (expires in 20 minutes).
  • include_documents_base64=1 — Embed document content inline as base64 (capped at 7 MB total).
  • report_type=base_64 — Also return the report PDF inline as base64.

overall_status_code values: 0 In progress · 1 Completed · 3 Awaiting Input · 4 Processing · 5 Discrepancy · 6 Completed with exception · 8 Closed · 9 On Hold · 10 Cancelled · 11 Consent missing · 12 Insufficient funds.

A candidate is finished at codes 1, 6, 8, or 10. Stop polling then.

check_status_code values: 0 Ready to initiate · 1 Verified · 2 Unable to Verify · 4 In Progress · 5 On Hold · 7 N/A · 9 Form submitted · -1 Insufficiency · -2 Major Discrepancy · -3 Minor Discrepancy.


5. GET /external/v1/candidate/report/pdf

Downloads the completed BGV report.

curl --location 'https://api-sa.in.springverify.com/external/v1/candidate/report/pdf?candidate_id=123456' \ --header 'Authorization: Bearer <YOUR_API_TOKEN>' \ --output report.pdf

Add &report_type=base_64 to get JSON with a base64-encoded PDF instead of a binary stream.

Async generation for large reports:

  1. POST /external/v1/candidate/report/pdf/initiate with { "candidate_id": 123456 } — returns a job_id.

  2. Poll GET /external/v1/candidate/report/pdf/status?job_id=<uuid> until data.status is completed.

  3. On completed, data.downloadUrl holds a pre-signed link (expires — download promptly).


Webhook report push

Instead of polling, SpringVerify can POST to your endpoint when a candidate reaches a final status. The payload includes: event, candidate_id, candidate_uuid, overall_status, overall_status_code, name, email, employee_id, report_url (signed, expires), completed_date, and meta_data.

  • By default, only final outcomes (code 1 and 6) trigger a push with event: "completed". Interim pushes can be enabled.
  • Map on overall_status_code, not overall_status (labels are inconsistently cased).
  • Your endpoint must respond 200, 201, 202, or 204. Be idempotent, keyed on candidate_id + overall_status_code.
  • Pushes are batched on a schedule — treat the webhook as an optimisation and reconcile periodically with GET /details.
  • To configure: share your endpoint URL, auth scheme, and any static headers with your SpringVerify point of contact.

Error handling

  • 400 — Malformed request or validation failure. Fix and do not retry.
  • 401 — Token missing, invalid, or expired. Returns { "msg": "...", "description": "..." }.
  • 404 — Candidate or resource not found.
  • 409 — Duplicate candidate or wrong state.
  • 413 — Payload too large (20 MB résumé; 7 MB base64 documents on GET /details).
  • 5xx — Temporary server issue; safe to retry with exponential backoff.

Known limitations

  • category_id on POST /add — Accepted but not returned by GET /details. Use tags or carry the value in meta_data.
  • UPPERCASE add-on keys — Pass validation but are not mapped to a check. Always send lowercase (e.g. employment).
  • skipped_checks as an array — Ignored. Send an object keyed by check name: { "employment_check": 1 }.

Testing & sandbox

A sandbox is available so you can build and test before going live. Request sandbox credentials from your SpringVerify point of contact. Sandbox checks are not run — statuses are moved manually by the backend. No charges apply.

When you go live, switch to the production host and token, then re-read GET /packages (ids differ between environments).


Migrating from older field names

An earlier version of the API used different field names. These are still translated for now but will be withdrawn:

  • files[{ original_file_url, document_tag }] → documents[{ url, tag }]
  • basic_details.phone_number → basic_details.mobile_number
  • identity.identity_candidate_name → identity.name_on_document
  • employment.company_legal_name → employment.company_name
  • address.<entry>.type → remove it; the type comes from the key
  • latitude / longitude as numbers → send as strings

For the full Postman collection, see documenter.getpostman.com.