# Records an audit-trail note only -- the session's status does NOT change.
curl -s -X POST https://verification.didit.me/v3/sessions/8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d/reviews/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"new_status": "In Review",
"comment": "Flagging for manual document re-check."
}'import os, requests
# Records an audit-trail note only -- the session's status does NOT change.
# To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.
session_id = "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d"
resp = requests.post(
f"https://verification.didit.me/v3/sessions/{session_id}/reviews/",
headers={
"x-api-key": os.environ["DIDIT_API_KEY"],
"Content-Type": "application/json",
},
json={
"new_status": "In Review",
"comment": "Flagging for manual document re-check.",
},
timeout=10,
)
resp.raise_for_status()
print(resp.json()) # {'user': 'Unknown', 'new_status': 'In Review', ...}// Records an audit-trail note only -- the session's status does NOT change.
// To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.
const sessionId = "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d";
const res = await fetch(
`https://verification.didit.me/v3/sessions/${sessionId}/reviews/`,
{
method: "POST",
headers: {
'x-api-key': 'YOUR_API_KEY',
"Content-Type": "application/json",
},
body: JSON.stringify({
new_status: "In Review",
comment: "Flagging for manual document re-check.",
}),
},
);
if (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);
console.log(await res.json()); // { user: 'Unknown', new_status: 'In Review', ... }<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/sessions/{session_id}/reviews/",
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([
'new_status' => 'In Review',
'comment' => 'Flagging for manual document re-check.'
]),
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/{session_id}/reviews/"
payload := strings.NewReader("{\n \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\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/{session_id}/reviews/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/sessions/{session_id}/reviews/")
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 \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\n}"
response = http.request(request)
puts response.read_body{
"user": "Unknown",
"new_status": "In Review",
"comment": "Flagging for manual document re-check.",
"created_at": "2026-06-12T00:18:44.466537Z"
}Create Session Review
Append a note to a User Verification (KYC) session’s review / activity feed. This endpoint only records an entry — it never changes the session. The session’s status is left untouched, no status-transition validation runs, and no webhook fires. To actually approve, decline, or re-open a session (which also writes a fully-attributed STATUS_UPDATED entry to this feed), use PATCH /v3/session/{session_id}/update-status/ instead.
Both body fields are optional and an empty JSON object is accepted. new_status is stored purely as a label on the entry and accepts any of the ten session status values (case-sensitive). @email mentions inside comment are stored as plain text only — they trigger no notifications on this endpoint, and the entry’s mentioned_emails stays empty.
Note on attribution: entries created here carry no actor information. In the feed they show actor_display: "Unknown", actor_type: "CONSOLE_USER", and activity_type: "STATUS_UPDATED" (storage defaults), and the 201 body’s user field is "Unknown".
# Records an audit-trail note only -- the session's status does NOT change.
curl -s -X POST https://verification.didit.me/v3/sessions/8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d/reviews/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"new_status": "In Review",
"comment": "Flagging for manual document re-check."
}'import os, requests
# Records an audit-trail note only -- the session's status does NOT change.
# To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.
session_id = "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d"
resp = requests.post(
f"https://verification.didit.me/v3/sessions/{session_id}/reviews/",
headers={
"x-api-key": os.environ["DIDIT_API_KEY"],
"Content-Type": "application/json",
},
json={
"new_status": "In Review",
"comment": "Flagging for manual document re-check.",
},
timeout=10,
)
resp.raise_for_status()
print(resp.json()) # {'user': 'Unknown', 'new_status': 'In Review', ...}// Records an audit-trail note only -- the session's status does NOT change.
// To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.
const sessionId = "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d";
const res = await fetch(
`https://verification.didit.me/v3/sessions/${sessionId}/reviews/`,
{
method: "POST",
headers: {
'x-api-key': 'YOUR_API_KEY',
"Content-Type": "application/json",
},
body: JSON.stringify({
new_status: "In Review",
comment: "Flagging for manual document re-check.",
}),
},
);
if (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);
console.log(await res.json()); // { user: 'Unknown', new_status: 'In Review', ... }<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/sessions/{session_id}/reviews/",
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([
'new_status' => 'In Review',
'comment' => 'Flagging for manual document re-check.'
]),
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/{session_id}/reviews/"
payload := strings.NewReader("{\n \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\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/{session_id}/reviews/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/sessions/{session_id}/reviews/")
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 \"new_status\": \"In Review\",\n \"comment\": \"Flagging for manual document re-check.\"\n}"
response = http.request(request)
puts response.read_body{
"user": "Unknown",
"new_status": "In Review",
"comment": "Flagging for manual document re-check.",
"created_at": "2026-06-12T00:18:44.466537Z"
}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.
Headers
Set to application/json when sending a JSON body.
"application/json"
Path Parameters
UUID of the User Verification (KYC) session. Must belong to the same application as the API key — cross-application UUIDs, deleted sessions, and Business Verification (KYB) session IDs all return 404.
"8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d"
Body
Optional status label to record on the entry. Accepts any session status value, case-sensitive ("approved" is rejected with 400). Recording a status here does not change the session's actual status — use the update-status endpoint for that.
Not Started, In Progress, Approved, Declined, In Review, Expired, Abandoned, Kyc Expired, Resubmitted, Awaiting User "In Review"
Optional free-text note (no enforced length limit). Stored verbatim; @email mentions are not processed on this endpoint.
"Flagging for manual document re-check."
Response
Entry recorded on the session's audit trail. The session itself is unchanged — its status keeps its previous value and no webhook is sent. The new entry also appears at the top of GET …/reviews/ (with actor_display: "Unknown").
Display name of the entry's author. Always "Unknown" for entries created through this endpoint, because it records no actor attribution.
"Unknown"
The status label recorded on the entry, or null if none was sent. The session's actual status is not affected.
Not Started, In Progress, Approved, Declined, In Review, Expired, Abandoned, Kyc Expired, Resubmitted, Awaiting User "In Review"
The note recorded on the entry, or null if none was sent.
"Flagging for manual document re-check."
When the entry was written, ISO 8601 UTC.
"2026-06-12T00:18:44.466537Z"