Report apparent CSAM to the NCMEC CyberTipline
When your platform encounters apparent child sexual abuse material (CSAM) in media, detection alone does not close the legal loop. US providers must report it to the National Center for Missing & Exploited Children (NCMEC) CyberTipline and preserve the report contents for 90 days. This runbook walks the full loop on Orbit: where the detection signal comes from, how to read the reporting obligation, how to assemble and preserve a filing-ready report with the two/api/v1/messages/media/csam-report endpoints, and which half of the work
belongs to you.
When the obligation applies to you
18 U.S.C. §2258A applies to providers of an electronic communication service or remote computing service to the public in the United States. If your organization uses Orbit to send or receive SMS, MMS, WhatsApp, RCS, or email media for US users, you are in that position, and the duty fires when your service encounters apparent CSAM. “Apparent” is the statutory standard: a credible automated or human detection signal triggers the reporting duty; you do not need certainty, and you do not investigate or adjudicate the material yourself. Orbit already produces the detection signals you need:- The vision-agent image pre-screen classifies uploaded and attached imagery
and withholds anything it flags as unsafe, including the
csamcategory. - The inbound media threat scan quarantines dangerous inbound MMS and attachment bytes before they reach an inbox or the message store (see Inbound media threat scan and quarantine model).
Where the detection signal comes from
The reporting endpoint recognizes four detection sources. Read them from the requirements endpoint (detection_sources) rather than hard-coding them.
Automated signals (
image_moderation_shield, media_threat_scan,
external_classifier) file only at or above the minimum confidence gate,
min_confidence (0.5 by default, returned by the requirements endpoint). A
signal below the gate is refused with a 422 so a borderline classifier verdict
is never filed as a statutory report on its own. If a human reviewer confirms
the material, resubmit with source: "analyst_review" and it files at any
confidence.
Media ingested before these scanning surfaces were live carries no automated
signal. For that older media, run your normal human review and file with
source: "analyst_review".
Read the reporting requirement
GET /api/v1/messages/media/csam-report/requirements returns the obligation
exactly as the platform models it: the statute, the preservation window, the
incident types, the report lifecycle states, the detection sources, the
required report elements, and the confidence gate. Read it at integration
time and when your compliance program is audited; it is the contract your
reporting pipeline codes against.
data object of the response:
required_elements list is what §2258A(b) contemplates in operator
language: who was involved and how they connected, when the material was
observed, where the sender appeared to be, the material itself identified by
hash, and the surrounding communication. The sections below show where each
element lands in the request.
Assemble and file a report
POST /api/v1/messages/media/csam-report assembles the filing-ready report
and preserves its summary for the statutory window in one call. The body has
three parts:
incident(required): the channel, direction, the message or conversation the material arrived on, when it was detected, and thedetectionblock:source,apparent_csam,confidencein [0, 1], and thedetectorthat produced the verdict.media(required, 1 to 50 items): each item carries at least one hash (md5,sha1,sha256, orphotodna), plus filename, content type, size, astorage_refpointing at the preserved bytes (never the bytes themselves), and when it was observed.subscriber(optional): the involved party’s contact reference, handle (MSISDN, email, or social handle), IP address, coarse location, and the timestamps the material was observed. Include what you lawfully hold; these are the §2258A(b)(1),(3) elements.reporter(optional): your ESP name, NCMEC-assigned ESP id, and contact details. Omitted fields fall back to your organization reference until you set your NCMEC-registered identity.
The quick brown fox jumps over the lazy dog; substitute the hashes of the
actual preserved file.
201 with the assembled report in data.
The report starts life assembled: built, preserved, and awaiting
transmission. preservation.preserve_until is the §2258A(h) deadline, 90
days after assembly. The data object:
422 and preserves nothing:
What Orbit does and what you do
The split is sharp, and it is the part of this runbook to get right before an audit. Orbit assembles the filing-ready artifact: it validates the detection signal against the confidence gate, normalizes the report to the CyberTipline shape, computes the 90-day preservation deadline, and preserves a PII-safe summary of the report (references and media hashes, not the subscriber’s handle, IP, or location) in your tamper-evident audit ledger. Orbit does not transmit anything to NCMEC on your behalf. You are the reporting ESP. Registration with NCMEC, the CyberTipline credentials, and the transmission step that moves a report fromassembled
through queued, submitted, and acknowledged are tenant-owned controls.
Evidence preservation and the 90-day window
§2258A(h) requires you to preserve the report contents and the involved material for 90 days. Every filed report writes a tamper-evident audit entry (actionmessages.csam_report.filed, resource csam_cybertip_report, keyed
by the ctr_… report id) carrying the incident classification, the detection
source and confidence, the media hashes, and preserve_until. Read it where
you read the rest of the ledger: Settings → Audit log in the dashboard,
or the async export covered in Audit Log Export;
the live filters are in Audit Log.
Two operational consequences:
- The preserved entry and the media it references outrank routine retention
purges for the statutory window. If your retention schedule or an erasure
request would delete the quarantined bytes or the audit entry before
preserve_until, the statutory preservation obligation wins for that window; coordinate erasure work with your pending reports. - The audit summary deliberately holds references, not the subscriber PII
the filing carries. The full report is reconstructable from the referenced
message at filing time, so keep the underlying message and media readable
until
preserve_untilas well.
Troubleshooting
422CSAM_REPORT_NOT_WARRANTED. Either apparent_csam was false or the
automated signal’s confidence was below min_confidence (0.5 by default;
read the live value from the requirements endpoint). If a human reviewer
confirms the material, resubmit the same body with
detection.source: "analyst_review"; human confirmations file at any
confidence.
400 on the media hashes. Every media item needs at least one of md5,
sha1, sha256, or photodna, and the hex hashes must be their full length
(32, 40, and 64 hex characters respectively). Hash the preserved bytes, not a
thumbnail or a transcode.
401 or 403. The GET requires your read scope and the POST your write
scope on Messages. Check the API key used by your reporting pipeline, not the
key your dashboard session uses.
No detection signal on older media. Media ingested before the scanning
surfaces were live has no automated verdict. File those after human review
with source: "analyst_review", and see
Tenant migration operations if your
organization still has a platform migration pending.