← Back to blog

No-Code KYC Workflow in Make.com: Webhook to Sequential ID Checks and Airtable

Build a Make.com KYC pipeline from a custom webhook through sequential Cryvis Passport, PAN, and Aadhaar checks into an Airtable applicant record.

Not every KYC intake lives in Typeform. Product backends, mobile apps, and partner portals often POST applicant packets to an automation layer. This guide builds a Make.com scenario that starts on a Custom webhook, runs sequential Cryvis identity checks, and writes a normalized applicant row to Airtable.

Sequential (not parallel) checks are useful when later steps depend on earlier results — for example, skip Aadhaar if passport already satisfies policy, or require PAN only for India-resident applicants.

For a Typeform + Router pattern into HubSpot, see Automate KYC in Make.com. Single-document deep dives: passport, PAN, Aadhaar.

Architecture

Your app / portal
      |
      |  POST multipart or JSON+URLs
      v
Make.com Custom Webhook
      |
      v
[1] Passport?  --> Cryvis /v1/documents/passport
      |
      v
[2] PAN?       --> Cryvis /v1/documents/pan
      |
      v
[3] Aadhaar?   --> Cryvis /v1/documents/aadhaar
      |
      v
Airtable: Applicants

Auth on every Cryvis call:

Authorization: Bearer YOUR_API_KEY
Base URL: https://api.cryvis.com

Step 1: Design the webhook contract

Add Webhooks → Custom webhook and copy the URL into your app. Prefer a JSON body that references file URLs your scenario can download, or have the client POST multipart directly to Make.

Example JSON contract:

{
  "applicant_id": "app_ ev_01",
  "email": "rahul@example.com",
  "country": "IND",
  "checks": ["passport", "pan", "aadhaar"],
  "files": {
    "passport_first_page": "https://storage.example/p1.jpg",
    "passport_last_page": "https://storage.example/p2.jpg",
    "pan": "https://storage.example/pan.jpg",
    "aadhaar_front": "https://storage.example/aadhaar-f.jpg",
    "aadhaar_back": "https://storage.example/aadhaar-b.jpg"
  }
}

Keep checks explicit. Guessing document type from filenames is brittle; see identity document processing if you must classify by MIME/filename.

Step 2: Download binaries

For each URL present, add HTTP → Get a file:

VariableSource URL
passport_firstfiles.passport_first_page
passport_lastfiles.passport_last_page
pan_filefiles.pan
aadhaar_1files.aadhaar_front
aadhaar_2files.aadhaar_back

Store Make file handles; do not pass remote URLs to Cryvis multipart fields — Cryvis expects uploaded binary parts.

Step 3: Airtable base

Create an Applicants table:

FieldType
Applicant IDSingle line (primary)
EmailEmail
CountrySingle line
Passport numberSingle line
Passport nameSingle line
Passport expiryDate
MRZ validCheckbox
PAN numberSingle line
PAN holder typeSingle line
Aadhaar numberSingle line
Aadhaar maskedCheckbox
Aadhaar addressLong text
KYC stageSingle select
Last errorLong text

KYC stage options: received, passport_done, pan_done, aadhaar_done, complete, blocked.

Step 4: Create the Airtable row early

Right after the webhook, Airtable → Create a record with:

  • Applicant ID, Email, Country
  • KYC stage = received

Updating one record through the chain keeps ops dashboards live as each check finishes.

Step 5: Sequential passport check

Router / Filter: continue only if checks contains passport and both passport URLs were provided.

HTTP → Make a request

SettingValue
URLhttps://api.cryvis.com/v1/documents/passport
MethodPOST
BodyMultipart/form-data
HeaderAuthorization: Bearer {{cryvis_api_key}}

Multipart (names are required exactly as shown):

PartBinary
first_pagepassport_first
last_pagepassport_last

Do not send a single file part — the passport endpoint rejects that shape.

Parse data:

passport_number     = data.passport_number
passport_full_name  = data.full_name
given_name          = data.given_name
surname             = data.surname
date_of_birth       = data.date_of_birth
nationality         = data.nationality
issue_date          = data.issue_date
expiry_date         = data.expiry_date
issuing_country     = data.issuing_country
sex                 = data.sex
mrz_line1           = data.mrz.line1
mrz_line2           = data.mrz.line2
mrz_valid           = data.mrz.check_digits_valid

Airtable → Update a record (same Applicant ID):

  • Passport fields above
  • KYC stage → passport_done
  • If mrz_valid is false → KYC stage blocked, Last error passport_mrz_invalid

Policy fork: some teams continue to PAN/Aadhaar even when MRZ fails; others stop. Encode the choice as a Filter after this step.

API reference: /docs/api/extractPassport · /apis/passport.

Step 6: Sequential PAN check

Filter: checks contains pan AND country is IND (or your rule) AND KYC stage is not blocked.

HTTP

SettingValue
URLhttps://api.cryvis.com/v1/documents/pan
Multipartfile = pan_file

Map from data:

pan_number        = data.pan_number
pan_full_name     = data.full_name
father_name       = data.father_name
pan_dob           = data.date_of_birth
holder_type_code  = data.holder_type_code
holder_type       = data.holder_type
# optional audit
pan_series        = data.pan_structure.series
pan_check_digit   = data.pan_structure.check_digit

Update Airtable → stage pan_done. Optionally compare pan_full_name to passport_full_name with a simple uppercase equality check; on mismatch set Last error name_mismatch_pan_passport without inventing fuzzy-match APIs Cryvis does not provide.

Docs: /docs/api/extractPan · /apis/pan.

Step 7: Sequential Aadhaar check (PII)

Filter: checks contains aadhaar AND stage not blocked.

HTTP

SettingValue
URLhttps://api.cryvis.com/v1/documents/aadhaar
Multipartfile = aadhaar_1; optional second file = aadhaar_2

Map:

aadhaar_number  = data.aadhaar_number
aadhaar_name    = data.full_name
dob             = data.date_of_birth
yob             = data.year_of_birth
gender          = data.gender
care_of         = data.care_of
address         = data.address
pincode         = data.pincode
is_masked       = data.is_masked

PII practices for Airtable:

  1. Enable field-level permissions; hide Aadhaar number from general editors.
  2. Prefer writing the value only when needed; if is_masked is true, store as-is and check Aadhaar masked.
  3. Do not mirror full Aadhaar into Make.com Data stores or public Slack messages.
  4. If your compliance pack forbids plain-text UID storage, write only last-4 derived in a Formula field and leave the raw field empty after a short TTL process outside Make.

Update Airtable → stage aadhaar_done, then a final module sets stage complete when all requested checks succeeded.

Docs: /docs/api/extractAadhaar · /apis/aadhaar.

Step 8: Webhook response

Enable Webhooks → Webhook response so your app gets a synchronous summary:

{
  "applicant_id": "app_ev_01",
  "kyc_stage": "complete",
  "passport_number": "P1234567",
  "pan_number": "ABCPS1234F",
  "aadhaar_masked": true,
  "mrz_valid": true
}

Omit raw Aadhaar from the HTTP response if the caller does not need it — Airtable remains the system of record.

Error handler pattern

Each Cryvis HTTP
      |
      +-- Success path --> Airtable update
      |
      +-- Error handler
            |
            +-- Airtable: Last error = status + message
            +-- KYC stage = blocked
            +-- Webhook response 502/424 with applicant_id

Typical root causes: missing last_page on passport, empty file on PAN, more than two Aadhaar files, expired Bearer token.

When to use sequential vs Router

PatternUse when
Sequential (this post)Later checks depend on earlier outcomes; single applicant packet
Router by type (automate KYC)One submission is exactly one document type
MIME/filename Router (identity processing)Unlabeled folder drops

CTA

Wire sequential Passport, PAN, and Aadhaar extraction with Cryvis: start at /apis/passport, /apis/pan, and /apis/aadhaar. Point Make's Custom webhook at your app, use Bearer auth against https://api.cryvis.com, and keep Airtable as the KYC ledger.