curl --request GET \
--url https://www.closient.com/epcis/api/2.0/verification/report \
--header 'X-API-Key: <api-key>'import requests
url = "https://www.closient.com/epcis/api/2.0/verification/report"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://www.closient.com/epcis/api/2.0/verification/report', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.closient.com/epcis/api/2.0/verification/report",
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://www.closient.com/epcis/api/2.0/verification/report"
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://www.closient.com/epcis/api/2.0/verification/report")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/epcis/api/2.0/verification/report")
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{
"by_decision": [],
"declined_attempts": 23,
"declined_distinct_units": 17,
"declined_units_with_price": 12,
"estimated_prevented_value": [
{
"amount": "2145.88",
"currency": "USD"
}
],
"period_end": "2026-10-01T00:00:00Z",
"period_start": "2026-09-01T00:00:00Z",
"period_truncated": false,
"time_zone": "America/Chicago",
"total_attempts": 431,
"total_distinct_units": 388
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Fraud-blocked returns report
Counts of returns-verification decisions for the authenticated organization over a selectable period, with the declined states surfaced as prevented return-fraud attempts and a dollar estimate where the units’ sale events carried a price.
Read the two counts as different questions. attempts is how many times the return desk asked; distinct_units is how many physical units were involved. The dollar estimate follows units, never attempts — a unit scanned three times is worth its price once.
Declined means exactly already_returned, never_sold, unknown_serial. recalled_lot is reported in by_decision like every other state but is deliberately not counted as prevented fraud: a recall block is product-safety handling, and a customer returning a unit that was later recalled is not attempting fraud.
The dollar figure is an estimate and is labelled as one. It sums the sale prices recorded on the sale events of the declined units, per currency, and never across currencies. declined_units_with_price states how much of the population it actually covers; never_sold and unknown_serial can never carry a price, because both mean this organization recorded no sale for that unit.
Dates are inclusive and resolved in time_zone (default UTC), so end covers the whole of that day locally. A span longer than 366 days is clamped to the most recent 366 days and flagged with period_truncated, and reversed bounds are ordered — neither is an error, and the window actually used is always echoed back. An unrecognised time_zone is rejected (422): falling back to UTC would move a retailer’s month boundary and land real transactions in the wrong month.
Results are computed only from the authenticated organization’s own outcomes. Caller must hold an OWNER or MANAGER membership.
curl --request GET \
--url https://www.closient.com/epcis/api/2.0/verification/report \
--header 'X-API-Key: <api-key>'import requests
url = "https://www.closient.com/epcis/api/2.0/verification/report"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://www.closient.com/epcis/api/2.0/verification/report', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.closient.com/epcis/api/2.0/verification/report",
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://www.closient.com/epcis/api/2.0/verification/report"
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://www.closient.com/epcis/api/2.0/verification/report")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.closient.com/epcis/api/2.0/verification/report")
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{
"by_decision": [],
"declined_attempts": 23,
"declined_distinct_units": 17,
"declined_units_with_price": 12,
"estimated_prevented_value": [
{
"amount": "2145.88",
"currency": "USD"
}
],
"period_end": "2026-10-01T00:00:00Z",
"period_start": "2026-09-01T00:00:00Z",
"period_truncated": false,
"time_zone": "America/Chicago",
"total_attempts": 431,
"total_distinct_units": 388
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}{
"detail": "The requested resource was not found.",
"error_code": "not_found",
"retryable": false,
"status": 404,
"timestamp": "2026-03-31T12:00:00+00:00",
"title": "Not Found",
"type": "https://closient.com/docs/errors/not_found"
}Authorizations
Query Parameters
First day to count, inclusive (YYYY-MM-DD). Defaults to 30 days before end. A span longer than 366 days is clamped to the most recent 366 days rather than refused, and the response sets period_truncated.
Last day to count, inclusive (YYYY-MM-DD). Defaults to today in time_zone. If end precedes start the two are ordered — two dates delimit one interval, and which was typed first is not a fact about the data.
IANA time zone the date range is resolved against, e.g. America/Chicago. A retailer's month ends at local midnight, not UTC midnight, and the difference lands real transactions in the wrong month.
64Response
OK
Tenant-scoped fraud-blocked report for one period.
First instant counted, in UTC. Inclusive.
First instant not counted, in UTC. Exclusive — it is midnight at the start of the day after the requested end date, so the whole of end is inside the report.
IANA time zone the requested date range was resolved against.
True when the requested span exceeded the maximum and the window above is the clamped one — the most recent allowed period. Every number in this response describes period_start..period_end, not the range that was asked for.
Every verify call in the period, all decision states.
Distinct units summed across states. A unit verified in two different states counts once in each, because those are two different events at the desk.
One entry per decision state, always all of them — a state with no activity reports zeroes.
Show child attributes
Show child attributes
Attempts that were declined return attempts (already_returned, never_sold, unknown_serial).
Distinct units behind declined_attempts.
Of declined_distinct_units, how many carried a recorded sale price.
Estimated value of the declined return attempts, per currency. An estimate, computed from the sale prices recorded on the units' own sale events — not a booked loss, and covering only declined_units_with_price of the declined units. recalled_lot is excluded: a recall block is product-safety handling, not a fraud attempt.
Show child attributes
Show child attributes