curl --fail \
https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/ \
-H 'x-api-key: YOUR_API_KEY' \
--output report.pdfimport requests
response = requests.get(
"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/",
headers={"x-api-key": "YOUR_API_KEY"},
stream=True,
timeout=60,
)
response.raise_for_status()
with open("report.pdf", "wb") as fh:
for chunk in response.iter_content(chunk_size=8192):
fh.write(chunk)import { writeFile } from 'node:fs/promises';
const response = await fetch(
'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/',
{ headers: { 'x-api-key': 'YOUR_API_KEY' } },
);
if (!response.ok) throw new Error(`PDF generation failed: HTTP ${response.status}`);
await writeFile('report.pdf', Buffer.from(await response.arrayBuffer()));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/session/{sessionId}/generate-pdf/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/session/{sessionId}/generate-pdf/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://verification.didit.me/v3/session/{sessionId}/generate-pdf/")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/session/{sessionId}/generate-pdf/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body"<string>"Generate PDF
Render and download a compliance-ready PDF report for a finished verification session. The same path serves both User Verification (KYC) and Business Verification (KYB) sessions — the server resolves the sessionId against both session types and picks the matching report template.
Eligible statuses. The session must already carry a final or reviewable status:
- KYC sessions:
Approved,Declined,In Review, orKyc Expired. - KYB sessions:
Approved,Declined, orIn Review.
Any other status (Not Started, In Progress, Expired, Abandoned, …) returns 403 with an explanatory detail string — see the 403 response below.
What the report contains. The PDF mirrors the console session view at the moment of the request:
- KYC — rolled-up session status, the warnings list, and one section per executed feature: ID Verification (document images plus extracted fields), NFC, Liveness, Face Match, Email Verification, Phone Verification, Proof of Address, Questionnaire answers, Database Validation, AML Screening, and IP Analysis — followed by session tags, console review activity (comments and status changes), and the session event timeline.
- KYB — registry checks (company data), AML screenings, business document verifications, key-people checks, questionnaire responses, phone/email verifications, IP analyses, and the session event timeline, followed by tags and review activity.
Branding. If your application has white-label customization, the report is rendered with your logo and links to your privacy-policy URL; otherwise it carries Didit branding. Reports are rendered in English — there is no language parameter.
No caching. Every call re-renders the PDF from the current session data, so a report generated after a manual review reflects the reviewer’s decision. Two calls for the same session can produce byte-different files — archive the downloaded file if you need an immutable copy.
Latency. Rendering downloads every stored image (document sides, selfies, extra files) before composing the PDF, so media-heavy sessions can take several seconds. Use a generous client read timeout (60 s recommended) and stream the body to disk.
Trailing slash. The canonical route ends with a trailing slash (…/generate-pdf/). A request without it is served directly with the same response — there is no 301 redirect, so no client has to follow redirects and curl does not need -L. Use the slashed URL as in the samples.
If you need the underlying data as JSON instead of a rendered report, use GET /v3/session/{sessionId}/decision/. For every reportable session of one user in a single document, use GET /v3/users/{vendor_data}/generate-pdf/.
curl --fail \
https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/ \
-H 'x-api-key: YOUR_API_KEY' \
--output report.pdfimport requests
response = requests.get(
"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/",
headers={"x-api-key": "YOUR_API_KEY"},
stream=True,
timeout=60,
)
response.raise_for_status()
with open("report.pdf", "wb") as fh:
for chunk in response.iter_content(chunk_size=8192):
fh.write(chunk)import { writeFile } from 'node:fs/promises';
const response = await fetch(
'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/',
{ headers: { 'x-api-key': 'YOUR_API_KEY' } },
);
if (!response.ok) throw new Error(`PDF generation failed: HTTP ${response.status}`);
await writeFile('report.pdf', Buffer.from(await response.arrayBuffer()));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/session/{sessionId}/generate-pdf/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/session/{sessionId}/generate-pdf/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://verification.didit.me/v3/session/{sessionId}/generate-pdf/")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/session/{sessionId}/generate-pdf/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body"<string>"KYC and KYB support
Works for both User Verification (KYC) and Business Verification (KYB) sessions. Didit routes to the appropriate PDF template automatically:- User Verification (KYC) session → report with ID verification, liveness, face match, AML, POA sections.
- Business Verification (KYB) session → report with company registry, key people (UBOs/officers), documents, AML, questionnaire, phone, email, and IP analysis sections when those features are part of the workflow.
Filename convention
| Kind | Filename |
|---|---|
| User | session_<session_id>.pdf |
| Business | business_<session_id>.pdf |
Content-Disposition: attachment; filename=... header.
Status requirement
The session must be inAPPROVED, DECLINED, or IN_REVIEW to generate a PDF. In-progress or not-started sessions return 403.
Examples
- User Verification (KYC) PDF
- Business Verification (KYB) PDF
curl https://verification.didit.me/v3/session/4c5c7f3a-.../generate-pdf/ \
-H "x-api-key: YOUR_API_KEY" \
-o kyc-report.pdf
curl https://verification.didit.me/v3/session/bs-01HJX1.../generate-pdf/ \
-H "x-api-key: YOUR_API_KEY" \
-o kyb-report.pdf
White-label
When the application has white-label customization enabled, the PDF uses your logo and privacy-policy URL. Configure at Console → Customization.Permission
Requiresread:sessions. Same scope for both kinds.
Related
- Sessions overview
- Retrieve session — JSON version of the same decision
- Download user history PDF — every reportable session of one user in a single file
- KYB response schema — fields included in business PDFs
Authorizations
Path Parameters
UUID of the User Verification (KYC) or Business Verification (KYB) session to render — the session_id returned by POST /v3/session/. The same path works for both session kinds; use the Content-Disposition filename on the response to tell which report type you received.
Must be a well-formed, lowercase UUID. The route only matches valid UUIDs, so a malformed value is rejected by the URL router before any application code runs and the response is a 404 HTML page rather than the JSON {"detail": ...} envelope shown below. The route's UUID converter only matches the canonical lowercase form — uppercase-hex UUIDs are rejected with the HTML 404.
"11111111-2222-3333-4444-555555555555"
Response
The rendered PDF document, returned directly as binary application/pdf — there is no JSON wrapper and no download-URL indirection. The body starts with the %PDF magic bytes (PDF 1.7). Save it to a .pdf file or stream it through to your caller.
The response is of type file.