curl -X POST \
https://verification.didit.me/v3/sessions/delete/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"session_numbers": ["1001", "1002", "1003"]
}'import requests
response = requests.post(
"https://verification.didit.me/v3/sessions/delete/",
headers={
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={"session_numbers": ["1001", "1002", "1003"]},
)
response.raise_for_status()
if response.status_code == 202: # more than 20 sessions: poll the job
job_id = response.json()["job_id"]
else: # 200: one result per matched session
print(response.json()["results"])
# Destructive: delete every KYC session in the application
# requests.post(
# "https://verification.didit.me/v3/sessions/delete/",
# headers={"x-api-key": "YOUR_API_KEY"},
# json={"delete_all": True},
# )const response = await fetch(
'https://verification.didit.me/v3/sessions/delete/',
{
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ session_numbers: ['1001', '1002', '1003'] }),
},
);
if (response.status !== 200 && response.status !== 202) throw new Error(`HTTP ${response.status}`);
const body = await response.json();
// 200: body.results, one per matched session. 202: poll /v3/sessions/delete/${body.job_id}/<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/sessions/delete/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'session_numbers' => [
'1001',
'1002',
'1003'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/sessions/delete/"
payload := strings.NewReader("{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/sessions/delete/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/sessions/delete/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02",
"session_number": 1001,
"face_retention_outcome": "deleted",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
},
{
"session_id": "b8e1d2c3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"session_number": 1002,
"face_retention_outcome": "retained_with_user",
"biometric_template_uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
"biometric_template_expires_at": "2027-10-09T10:15:00Z",
"deleted_child_verifications": 0
},
{
"session_id": "7a1e9c2d-5f4b-4c3a-8e2d-1b0a9f8e7d6c",
"session_number": 1003,
"face_retention_outcome": "ineligible_no_vendor_user",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
},
{
"session_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
"session_number": 1004,
"face_retention_outcome": "failed_retryable",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
}
]
}Batch Delete Sessions
Delete many KYC sessions by session number or all at once. Up to 20 return a per-session outcome; larger selections run as a deletion job you poll.
curl -X POST \
https://verification.didit.me/v3/sessions/delete/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"session_numbers": ["1001", "1002", "1003"]
}'import requests
response = requests.post(
"https://verification.didit.me/v3/sessions/delete/",
headers={
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
json={"session_numbers": ["1001", "1002", "1003"]},
)
response.raise_for_status()
if response.status_code == 202: # more than 20 sessions: poll the job
job_id = response.json()["job_id"]
else: # 200: one result per matched session
print(response.json()["results"])
# Destructive: delete every KYC session in the application
# requests.post(
# "https://verification.didit.me/v3/sessions/delete/",
# headers={"x-api-key": "YOUR_API_KEY"},
# json={"delete_all": True},
# )const response = await fetch(
'https://verification.didit.me/v3/sessions/delete/',
{
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ session_numbers: ['1001', '1002', '1003'] }),
},
);
if (response.status !== 200 && response.status !== 202) throw new Error(`HTTP ${response.status}`);
const body = await response.json();
// 200: body.results, one per matched session. 202: poll /v3/sessions/delete/${body.job_id}/<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/sessions/delete/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'session_numbers' => [
'1001',
'1002',
'1003'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/sessions/delete/"
payload := strings.NewReader("{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/sessions/delete/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/sessions/delete/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"session_numbers\": [\n \"1001\",\n \"1002\",\n \"1003\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02",
"session_number": 1001,
"face_retention_outcome": "deleted",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
},
{
"session_id": "b8e1d2c3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"session_number": 1002,
"face_retention_outcome": "retained_with_user",
"biometric_template_uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
"biometric_template_expires_at": "2027-10-09T10:15:00Z",
"deleted_child_verifications": 0
},
{
"session_id": "7a1e9c2d-5f4b-4c3a-8e2d-1b0a9f8e7d6c",
"session_number": 1003,
"face_retention_outcome": "ineligible_no_vendor_user",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
},
{
"session_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
"session_number": 1004,
"face_retention_outcome": "failed_retryable",
"biometric_template_uuid": null,
"biometric_template_expires_at": null,
"deleted_child_verifications": 0
}
]
}Behavior
Each matched session is deleted exactly as by Delete Session: the session, every verification attempt it holds, its decision and extracted data, its feature records, and all of its stored files are deleted, it disappears from every read endpoint, and previously issued media URLs stop resolving. Webhook deliveries still queued for a deleted session, and their retries, are dropped; webhooks already delivered are not affected. Deletion is permanent and irreversible. The number of matching sessions decides how the request is answered, whether you select them withsession_numbers or with delete_all:
| Matching sessions | Response |
|---|---|
| Up to 20 | 200 OK once they are deleted, with one result per matched session in results. |
| More than 20 | 202 Accepted with a deletion job. The sessions are deleted in the background; poll Get Session Deletion Job until it finishes. |
face_retention_outcome is failed_retryable: that session was not deleted and is still in place, so treat that result as a failure to retry, never as deletion confirmation.
Numbers that do not match a live KYC session in your application are skipped and do not appear in results.
Retention and instruction fields
The endpoint accepts the same optional fields as the single-session endpoint and applies them to every matched session:| Field | Type | Description |
|---|---|---|
retain_face_embeddings | boolean or null | Override the application’s face_retention_policy for this request. |
face_retention_days | integer (1-3650) | Finite retention duration for retained templates. Required when retaining unless the application sets face_retention_days. |
face_retention_deadline | datetime (ISO 8601) | Optional hard expiry, must be in the future. |
deletion_instruction | operational_session_delete (default) or privacy_erasure | privacy_erasure purges every retained template for each session’s User before deleting the session and cannot be combined with retain_face_embeddings: true. |
instruction_id | string (max 255) | Your durable reference for this instruction. Recorded on the audit trail and on every retained template. |
expires_at is computed, and what a privacy-erasure instruction does.
Per-session outcomes
For up to 20 matching sessions,200 OK returns one result per session:
{
"results": [
{ "session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02", "session_number": 1001, "face_retention_outcome": "deleted", "biometric_template_uuid": null, "biometric_template_expires_at": null, "deleted_child_verifications": 0 },
{ "session_id": "b8e1d2c3-4f5a-4b6c-8d7e-9f0a1b2c3d4e", "session_number": 1002, "face_retention_outcome": "retained_with_user", "biometric_template_uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b", "biometric_template_expires_at": "2027-10-09T10:15:00Z", "deleted_child_verifications": 0 },
{ "session_id": "7a1e9c2d-5f4b-4c3a-8e2d-1b0a9f8e7d6c", "session_number": 1003, "face_retention_outcome": "ineligible_no_vendor_user", "biometric_template_uuid": null, "biometric_template_expires_at": null, "deleted_child_verifications": 0 },
{ "session_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f", "session_number": 1004, "face_retention_outcome": "failed_retryable", "biometric_template_uuid": null, "biometric_template_expires_at": null, "deleted_child_verifications": 0 }
]
}
biometric_template_expires_at is when a retained template is deleted, and deleted_child_verifications is always 0 here because this endpoint deletes KYC sessions only.
face_retention_outcome | Meaning |
|---|---|
deleted | The session and its face embedding are deleted. Default behavior. |
retained_with_user | The session is deleted. One image-free biometric template stays anchored to the User; its id is biometric_template_uuid. |
none | The session had no face embedding to delete or retain. |
ineligible_no_vendor_user | Retention was requested, but the session is not linked to a User, so nothing can anchor a template. The session and its embedding are deleted. |
failed_retryable | The group this session was deleted with could not be deleted, because a storage service, a biometric store, or a monitoring provider was unavailable. This session is not deleted and is still in place. Re-run the request for it; retries converge on a single template. |
failed_retryable; the other groups are unaffected and stay deleted.
Large selections run as a job
When more than 20 sessions match, the response is202 Accepted with a deletion job instead of results:
{
"job_id": "5b8f2c1e-7d3a-4f6b-9e2c-1a0d8f7e6c5b",
"status": "PENDING",
"total": 250,
"processed": 0,
"outcomes": { "deleted": 0, "none": 0, "retained_with_user": 0, "ineligible_no_vendor_user": 0, "failed_retryable": 0, "already_deleted": 0 },
"deleted_child_verifications": 0,
"error": null,
"created_at": "2026-10-09T10:15:00Z",
"completed_at": null
}
status is COMPLETED or FAILED.
- The job reports how many sessions ended in each outcome, never which sessions it deleted.
- A
delete_alljob deletes only the sessions created before your request. Sessions started while it runs are not deleted. - The retention and instruction fields of your request apply to every session the job deletes.
- If a group cannot be deleted yet, the job retries it by itself.
- A
FAILEDjob explains why inerror. The sessions it had not reached are still in place: repeat the request to delete them.
Examples
- Delete by number
- Delete and retain templates
- Privacy erasure
- Delete all and poll the job
curl -X POST https://verification.didit.me/v3/sessions/delete/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"session_numbers": ["1001", "1002", "1003"]}'
curl -X POST https://verification.didit.me/v3/sessions/delete/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_numbers": ["1001", "1002"],
"retain_face_embeddings": true,
"face_retention_days": 365,
"instruction_id": "post-approval-cleanup-2026-08"
}'
curl -X POST https://verification.didit.me/v3/sessions/delete/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"session_numbers": ["1001"],
"deletion_instruction": "privacy_erasure",
"instruction_id": "dsar-2026-0142"
}'
curl -X POST https://verification.didit.me/v3/sessions/delete/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"delete_all": true}'
# More than 20 sessions matched: the response is 202 with a job_id.
curl https://verification.didit.me/v3/sessions/delete/JOB_ID/ \
-H "x-api-key: YOUR_API_KEY"
Migration from 204 responses
Until this release the endpoint returned204 No Content. It now returns 200 OK with results[], or 202 Accepted with a deletion job for more than 20 matching sessions. Update clients that assert on 204. The default deletion behavior is unchanged: existing applications stay on delete_with_session until you explicitly change the policy.
Related
Authorizations
Your application's API key, from Developers -> API keys in the Business Console. The primary key has full access. A named key can be scoped: none, read or write per resource, limited to some workflows or to approved sessions, to a list of IP addresses, and to an expiry date. 401 means the key is missing, wrong, revoked or expired; 403 means the key has no access to this resource or action, or the request came from an address outside its IP list; 404 on a session route means the session is outside the key's workflows or statuses. A key without media access receives image, video and PDF URLs as null, and a key without sessions write receives session links and tokens as null. See https://docs.didit.me/console/api-keys.
Body
Numeric session_number values of the KYC sessions to delete, as digit-only strings (JSON numbers are also accepted and coerced). Required unless delete_all is true; an empty list returns 400. Any non-digit entry rejects the whole request with 400 (unless delete_all is true, in which case validation is skipped and the entries are ignored). Numbers that do not match a live session in your application are silently skipped.
1^[0-9]+$["1001", "1002", "1003"]
When true, every remaining KYC session in the calling application is deleted and session_numbers is ignored. More than 20 matching sessions run as a deletion job (202) that covers only the sessions created before the request. Defaults to false. Irreversible; there is no confirmation step.
false
Override the application's face_retention_policy for this deletion. true keeps one image-free face biometric template anchored to the session's User after the session is deleted; false deletes the face embedding with the session; omit or null to follow the application policy. Ignored for KYB sessions and for sessions without a face embedding.
true
Finite retention duration, in days, for a retained template. Required when a template is retained unless the application already sets face_retention_days. The template's expires_at is the earliest of this duration, the application's general data-retention window, and face_retention_deadline.
1 <= x <= 3650365
Optional hard expiry for a retained template. Must be in the future.
"2027-08-28T00:00:00Z"
The class of instruction you are giving. operational_session_delete deletes the session and retains a template only when the policy or retain_face_embeddings says so. privacy_erasure purges every retained biometric template anchored to the session's User before deleting the session, cannot be overridden by the application policy, and cannot be combined with retain_face_embeddings: true (400).
operational_session_delete, privacy_erasure "operational_session_delete"
Your durable reference for this deletion instruction (for example an erasure-ticket id). Recorded on the audit trail and on any retained template. Generated by Didit when omitted.
255"dsar-2026-0142"
Response
Up to 20 sessions matched and were processed in the request. One result per matched session; numbers that matched nothing (unknown or already deleted) are skipped and do not appear. A result confirms deletion except when face_retention_outcome is failed_retryable: that session was NOT deleted and should be retried.
Show child attributes
Show child attributes