Skip to main content
Version: v3

Migrate to Verify v3

API changes​

The v3 API brings numerous breaking changes over the v2 API. It introduces a completely different API surface, both for requests and responses, aiming to simplify things for the end user, and to make responses more clear.

This document lists how the API has changed, and what you need to change in your v2 integration to start using v3.

For a full API reference and OpenAPI schema, see:

note

We will use the us-east server to illustrate with examples, but they all apply to other servers as well. Check your region.

New URL​

The new verification endpoint is /api/v3/verify.

v2v3
https://us-east.verify.microblink.com/api/v2/docverhttps://us-east.verify.microblink.com/api/v3/verify

In addition to the verification endpoint, the API also has an extraction-only endpoint; see the Extraction API section.

Schema​

Get the OpenAPI specification here.

Changes in the request​

Only multipart​

In v2, you had three ways to send an image: as a URL, as a base64-encoded string, or as a multipart/form-data upload.

The v3 API accepts only multipart uploads. It doesn't support uploading images as base64-encoded blobs, nor does it support passing images using a URL.

curl https://us-east.verify.microblink.com/api/v3/verify \
--request POST \
--header 'Authorization: Basic <credentials>' \
--form 'imageFirstSide=@front_id.jpg' \
--form 'imageSecondSide=@back_id.png'

Changes in request parameters​

JSON object in multipart upload​

In v2, you used application/json for the request and uploaded a JSON object with the configuration.

In v3, you use multipart/form-data and pass a (JSON-encoded) configuration object as one of the form-data fields.

Using configuration.json as an example:

configuration.json
{
"verification": {
"useCase": {
"verificationPolicy": "HighAssurance",
"verificationContext": "Remote",
"manualReviewStrategy": "RejectedOnly"
},
"settings": {
"rejectExpiredDocuments": true,
"screenPresenceSensitivity": "Level5",
"dataMatchSensitivity": "Level7"
}
},
"extraction": {
"redactionSettings": {
"globalMode": "ImageOnly"
},
"documentCaptureModuleSettings": {
"documentImageReturnEnabled": true,
"faceImageExtractionEnabled": true
}
}
}

The request looks like this now:

curl https://us-east.verify.microblink.com/api/v3/verify \
--request POST \
--header 'Authorization: Basic <credentials>' \
--form 'imageFirstSide=@front_id.jpg' \
--form 'imageSecondSide=@back_id.png' \
--form 'configuration=@configuration.json;type=application/json'

Renamed and removed parameters​

  • imageFront is renamed to imageFirstSide
  • imageBack is renamed to imageSecondSide
  • imageBarcode has the same name
  • a configuration field has been added; configuration.verification and configuration.imageAssessment are relevant for this migration guide
  • options is renamed to settings and moved to configuration.verification
  • useCase is moved to configuration.verification
  • captureSessionId and sessionID are removed; use traceId to correlate a request with your own records

Changes in use cases​

  • All use cases no longer support "Unknown" as a value.
  • verificationContext is unchanged.
  • manualReviewStrategy is unchanged.
  • manualReviewSensitivity has been removed.
  • documentVerificationPolicy has changed, see below
  • captureConditions has changed, see below
Verification policy​

documentVerificationPolicy is renamed to verificationPolicy.

Its allowed values are now:

  • "HighConversion" (previously "Permissive")
  • "Balanced" (previously "Standard")
  • "HighAssurance" (previously "Strict"/"VeryStrict")
warning

Because the boundaries of verificationPolicy moved (3 values vs. 4 previously), re-tune rather than re-map. Run a sample of known-good and known-fraudulent documents through your candidate policy and compare verdicts before you switch production traffic.

Capture conditions​

captureConditions has been renamed to cropAffectsVerdict and moved to configuration.verification.settings.

It also changes shape, not just name.

In v2 it was an enum (NoControl, Basic, Hybrid).

In v3, cropAffectsVerdict is a boolean and answers one question: can a cropped document receive an "Accept" in its verdict?

If cropAffectsVerdict is true (default), a cropped document will not be accepted; it can only be rejected or sent to manual review. If cropAffectsVerdict is false, a cropped document can be accepted.

Changes in options (settings)​

The v2 options object splits in two. Verification tuning goes to configuration.verification.settings; everything about extracted data and returned images goes under configuration.extraction.

Every MatchLevel becomes a Sensitivity. The values are unchanged (Level1 through Level10, and Disabled), except that Unknown is no longer accepted.

All sensitivity values default to "Level5", except barcodeAuthenticityCheck which remains at a default of "Level7".

  • options.screenMatchLevel is now verification.settings.screenPresenceSensitivity
  • options.photocopyMatchLevel is now verification.settings.photocopySensitivity
  • options.barcodeAnomalyMatchLevel is now verification.settings.barcodeAuthenticitySensitivity
  • options.photoForgeryMatchLevel is now verification.settings.portraitForgerySensitivity
  • options.dataMatchMatchLevel is now verification.settings.dataMatchSensitivity
  • options.generativeAiMatchLevel is now verification.settings.generativeAiSensitivity

The seven image-quality match levels collapse into one setting. blurMatchLevel, glareMatchLevel, lightingMatchLevel, sharpnessMatchLevel, handOcclusionMatchLevel, dpiMatchLevel, and tiltMatchLevel are all replaced by imageAssessment.imageQualitySensitivity, which applies uniformly to every image-quality dimension.

Renamed:

  • treatExpirationAsFraud is now verification.settings.rejectExpiredDocuments
  • imageQualityInterpretation is now imageQualityRetryPolicy
    • VeryHighConversion has been removed
    • the rest of the values are renamed and describe when to ask for a retake: NeverRetryBadQuality, RetryBadQualityAlways, RetryBadQualityForAcceptances, and RetryBadQualityForRejections.

Moved under extraction:

  • returnFullDocumentImage is now extraction.documentCaptureModuleSettings.documentImageReturnEnabled
  • returnFaceImage is now extraction.documentCaptureModuleSettings.faceImageExtractionEnabled
  • returnSignatureImage is now extraction.vizModuleSettings.signatureImageExtractionEnabled
  • anonymizationMode is now extraction.redactionSettings.globalMode, with its values unchanged (None, ImageOnly, ResultFieldsOnly, FullResult)

Removed:

  • staticSecurityFeaturesMatchLevel: the check still runs and is still reported, at verification.checks.visualCheck.securityFeaturesCheck, but it is no longer tunable
  • returnImageFormat, and the ImageFormat multipart field: returned images are always base64-encoded JPG
Cloud only

The consent object is mandatory if you use the cloud API. For self-hosted deployments, it isn't used.

v2 had no consent concept. In v3, a cloud request registers the consent you collected from the end user, as a consent text form value alongside the images.

consent
{
"userId": "<your-id-for-the-end-user>",
"durationDays": 365,
"givenOn": "2026-07-31T09:00:00Z",
"note": "User agreed to identity verification terms.",
"customerContext": {
"customerId": "<your-customer-id>",
"transactionId": "<your-transaction-id>"
}
}
curl https://us-east.verify.microblink.com/api/v3/verify \
--request POST \
--header 'Authorization: Basic <credentials>' \
--form 'imageFirstSide=@front_id.jpg' \
--form 'imageSecondSide=@back_id.png' \
--form 'consent={
"userId": "<your-id-for-the-end-user>",
"durationDays": 365
}'

Only two properties are required:

  • userId: your own unique identifier for the end user granting consent
  • durationDays: how long the consent stays valid, used to calculate its expiry

The rest are optional. givenOn timestamps when consent was granted, note records the agreement text or statement the user accepted, and customerContext links the record to your own customerId and transactionId.

Because userId is your identifier, this is the field that ties consent records to a person in your system, so it should be stable across requests for the same end user.

Requests that don't send a consent object return a 400 response.

For the full field reference and the error responses consent can produce, see Get your users' consent.

Changes in the response​

For a field-by-field walkthrough of the v3 response rather than a migration diff, see Interpret the response.

verdict replaces recommendedOutcome​

In v2, verification.recommendedOutcome carried the overall decision.

In v3, the decision is verification.verdict.

Two values are renamed, and Unknown is gone:

  • Undeterminable is now Unverifiable
  • ManuallyReview is now Review
  • Accept, Reject, and Retry are unchanged

certaintyLevel is no more​

In v2, you would inspect verification.certaintyLevel to assess how certain the verification process was.

In v3, this field no longer exists, and all verifications can be considered to be of high certainty.

Checks are a structured object, not a flat array​

In v2, checks was an array of Check objects, each identified by a name string and able to nest further checks in its own checks array. Finding a specific check meant walking the array and matching on names.

In v3, verification.checks is a typed object with four named groups:

v3
{
"verification": {
"verdict": "Reject",
"failedChecks": ["checks.extractedDataCheck.matchCheck.dateOfBirthCheck"],
"checks": {
"extractedDataCheck": {},
"documentLivenessCheck": {},
"visualCheck": {},
"documentValidityCheck": {}
}
}
}

Each group has named sub-checks, so a check you care about has a stable path instead of a position in an array. result keeps its v2 values, Pass, Fail, and NotPerformed, minus Unknown.

verification.failedChecks is new and has no v2 equivalent. It lists the flattened path of every check that ran and failed, which is the quickest way to find why a document was rejected without walking the tree.

Tiered checks report a threshold, not a level​

In v2, a TieredCheck carried a matchLevel telling you the level at which the check was evaluated.

In v3, a tiered check carries passesAtOrBelowSensitivity: the highest sensitivity at which this check would still pass.

Instead of seeing which level you configured, you see what you would have had to configure for this document to pass, which is what you need in order to re-tune.

Process indicators become image assessment​

V2 returned a processIndicators array of named indicators, resolving to Pass, Fail, Warn, or NotPerformed.

V3 replaces it with a top-level imageAssessment object holding three checks:

v3
{
"imageAssessment": {
"imageQualityCheck": { "result": "Pass" },
"croppedDocumentCheck": {
"result": "Pass",
"firstSide": { "result": "Pass" },
"secondSide": { "result": "Pass" }
},
"handPresenceCheck": { "result": "Pass" }
}
}

The Warn result has no v3 equivalent: a check either passes, fails, or wasn't performed.

Images are keyed, not listed​

v2 returned images as an array of { name, base64 } pairs, so you looked an image up by its name.

v3 returns an object with a key per image, and the value is the base64 string directly:

  • face
  • signature
  • firstSideCropped
  • secondSideCropped
  • barcode

Extracted data is typed​

This is the largest change in the response.

v2 returned extraction results as generic containers: extraction.overall, extraction.mrz, and extraction.barcode were arrays of Result objects, each a { type, field, details } bag that could nest more Result objects, with the field identified by a FieldValueType string. Reading a first name meant finding the entry whose field was FirstName.

In v3, extracted data is a typed object with named properties, so for example a first name is at extraction.result.firstName. Per-side and per-module results move under extraction.result.subResults.{side}.{viz,mrz,barcode}, and the document class moves to extraction.result.documentClassInfo.

The per-script values that v2 expressed with ExtractedScript (Latin, Cyrillic, Arabic, Greek) are now the lowercase keys of an AlphabetString:

v3
{
"extraction": {
"result": {
"firstName": { "latin": "JOHN" }
}
}
}

extraction.recognitionStatus, which carried the v2 ResultState (Empty, Uncertain, Valid, StageValid), is removed. Use extraction.processingStatus instead.

Configuration echo​

V2 returned optionsUsed and useCaseUsed as two separate objects.

V3 returns a single configurationUsed that mirrors the structure of the configuration you sent, so the effective value of a setting is at the same path you would have used to set it.

tip

Currently we don't indicate the defaults in the schema, so reading configurationUsed is also a reliable way to discover the default configuration.

Pipeline status replaces the root processing status​

v2 had a root-level processingStatus describing the run as a whole, with values like Completed, PartiallyCompleted, ExtractionFailed, CompletedAfterFront, and ServerModelError.

v3 splits this into a pipeline object with one entry per stage, each carrying its own status:

v3
{
"pipeline": {
"extraction": { "status": "Completed" },
"verification": { "status": "Completed" }
}
}

CompletedAfterFront has no v3 equivalent, because a v3 request carries all of its images at once and is processed as a whole.

Messages lose their status​

  • Messages were revised to be more consistent and informative, and they will also be appearing more often with the intention of guiding and providing additional feedback where individual checks/settings or their use in conjunction might be confusing.
  • Clients should not build validations or business logic on messages.
  • messages.status field is gone.
  • Error messages are removed.

See the current supported messages.

New response codes​

Three status codes are worth handling before you switch. These apply to both the cloud and self-hosted deployments.

503 is returned when the workers aren't ready to accept a request. In v2, 503 came only from the /health/live and /health/ready endpoints, never from a verification request, so a client that treats it as "endpoint down" rather than "retry shortly" needs adjusting.

413 is new, for payloads over the size limit.

429 itself is not new, since v2 returned it when the rate limit was exceeded. What's new is that v3 documents a Retry-After header carrying a suggested delay in seconds, and distinguishes two limiters: the memory-pressure limiter returns a JSON error body, while the concurrency limiter can return an empty one. If you already handle 429, check that your client tolerates an empty body and reads Retry-After rather than using a fixed backoff.

Changes in self-hosted deployment​

New image​

The self-hosted deployment now bundles the self-hosted extraction API, and has changed its name.

Grab it here:

docker pull us-docker.pkg.dev/document-verification-public/on-prem/core:4000.0.0

The new GitHub repo with the Helm charts and other deployment-related information is here.

git clone https://github.com/microblink/on-prem-ops.git

Licensing​

Your existing licenses and license environment variables are unchanged.

Single-image​

If you're still on a release earlier than 3.19.0, you're moving from the multi-service stack at the same time. Remove the old conf/doc-ver-api, conf/doc-ver-runner, and conf/bundle-doc-ver directories as part of that move. See On-prem deployment for how the current image is deployed.

The container reports its own sizing in the runtime object of every response (workerCount, inflightLimit, cpus, ram, and others), which is useful when you are capacity planning against v2 numbers.

Extraction API​

V2 was verification-only. V3 adds an extraction-only endpoint, POST /api/v3/extract, which runs the extraction half of the pipeline and skips verification.

It's the right endpoint if you only need the data off the document and don't need a verdict. The extraction results are identical in shape to the extraction object of a verification response, so you can move between the two endpoints without changing your parsing.

The extraction endpoint accepts only the extraction and imageAssessment sections of the configuration; verification settings are rejected. There is also a barcode-only endpoint, POST /api/v3/extract-barcode.

If you are coming to this endpoint from the standalone self-hosted extraction API rather than from Verify v2, see Migrate from self-hosted extraction API, which covers that migration in full.