How a case moves
A DigiFIR case is one record on the ledger that every institution adds to, from the complaint to the court's final order. Each step is a signed action. Each action either moves the case to a new status or adds a new version of the record at the same status. Nothing is overwritten, and police cannot move a case backwards: only a court order can.
The whole journey
1. The citizen files a complaint
The citizen proves their identity once, through DigiLocker or Meri Pehchaan, or in person at a police station. The citizen app then makes a signing key inside the phone's secure hardware. The ledger registers a decentralised identifier (DID) for the citizen, but no identity data.
The citizen fills in the complaint in eight guided steps: complainant, address, victim, place, date and time, what happened (with photos, videos, files or a voice note), the accused, and a summary to check before confirming. Attachments are hashed and encrypted on the phone before upload. When the citizen confirms, the app signs the complaint and sends it.
The fir-registry chaincode checks the signature and stores the complaint with status FILED. The narrative and personal details go into the private data collection of the state concerned. The shared ledger gets only their salted hash. The citizen receives a complaint number such as CMP-RJ-JAI-PS07-2026-000123, with the block and transaction that hold it.
NOTE
Under BNSS section 173(1)(ii), information given electronically has to be signed by the informant within three days. The app shows a "Sign your complaint" card for this, with Aadhaar eSign or a signature at the police station.
2. The station decides
The complaint reaches the front desk of the station it was addressed to. The duty officer or station house officer (SHO) reads it and chooses a legal route:
| Route | Action on the ledger | New status | Legal basis |
|---|---|---|---|
| Register an FIR | fir.register, with the BNS sections and the CCTNS FIR number | REGISTERED | BNSS s.173(1) |
| Register a Zero FIR and transfer it | fir.register_zero; the jurisdiction registry picks the receiving station | ZERO_FIR_TRANSFERRED, then REGISTERED at that station | BNSS s.173(1) |
| Preliminary enquiry | complaint.enquiry_request, then the supervising officer's approval | UNDER_ENQUIRY (14 days) | BNSS s.173(3) |
| Non-cognizable report | complaint.ncr | NCR_RECORDED | BNSS s.174 |
| Ask the informant for details | complaint.ask | unchanged |
A complaint recorded as an NCR, or one whose enquiry has closed, can still become an FIR later on the same record.
Probable duplicates
Before an FIR is registered, the police app shows duplicate hints. A hint appears when an attachment has the same SHA-256 hash as one on another case, or when a hint service finds similar text within the same state. Hints are advisory and never block anything, and the citizen app never shows them. The officer chooses one of three things:
- register the FIR;
- register it and send the pair to a magistrate for review;
- keep the complaint for the magistrate without registering ("Same incident: keep for the magistrate"). The complaint gets a
RIVAL-reference and statusREFERRED.
The magistrate then decides. "Same incident" links the complaint to the existing case (LINKED). "Different incident" sends it back to the station, which registers it as its own FIR.
3. Investigation
The SHO assigns an investigating officer (IO), and the case moves to UNDER_INVESTIGATION. The IO then records the investigation on the ledger:
- case diary entries, chained by hash so none can be removed (BNSS s.192);
- witness statements (s.180);
- arrests with their safeguards, production before the magistrate within 24 hours, remand and release (s.36, s.47, s.48, s.58, s.187);
- seizures, with the e-Sakshya recording's hash (s.105).
Statutory clocks run on the ledger: the 24-hour production limit, the default-bail day at 60 or 90 days from the first remand, two months for the offences s.193(2) lists, and the 90-day progress update to the informant. A missed deadline cannot be erased by a later action.
4. Evidence and the forensic laboratory
Every exhibit has a chain of custody made of two-party hops. The person handing an exhibit over signs an offer, and the receiver signs an acceptance. Both signatures stay on the ledger.
- The IO seizes the exhibit (
evidence.seize) and deposits it in the station's malkhana (a custody hop to the malkhana in-charge). - The malkhana in-charge hands the sealed parcel to the officer taking it to the laboratory, and the station dispatches it (
lab.dispatch). - Laboratory reception checks the seal, the papers and the contents, then accepts the parcel (
lab.accept) or refuses it with reasons (lab.refuse). The parcel goes back unopened if refused. - The analyst records each examination stage (
lab.stage). Working notes stay in a collection only the laboratory can read. - The analyst seals the report (
lab.seal). Its hash goes on the shared ledger and its text into a collection the state police, the laboratory and the judiciary share. The IO can read it only after sealing. - The exhibit goes back to the police in another two-party hop.
5. Final report and the court
The IO files a final report (fir.final_report): a chargesheet (CHARGESHEET_FILED) or a closure report (CLOSURE_REPORT_FILED). Both reach the magistrate's court app.
| Magistrate's decision | Action | New status |
|---|---|---|
| Take cognizance of a chargesheet (opens the case in eCourts with a CNR number) | court.cognizance | IN_COURT |
| Accept a closure report | court.closure_decide ACCEPT | DISPOSED |
| Order further investigation | court.closure_decide FURTHER_INVESTIGATION | back to UNDER_INVESTIGATION (s.193(9)) |
| Record disposal after trial | court.dispose | DISPOSED |
| Record a High Court order quashing the FIR | court.quash_record | QUASHED |
| Remand, bail, transfer of investigation, status request | court.remand, court.bail, court.transfer, court.status_request | unchanged |
Each of these court actions is recorded by the judicial-actions chaincode, which updates the case in fir-registry in the same transaction.
Status of a case
The diagram is simplified. A quash can come from any status from ZERO_FIR_TRANSFERRED to IN_COURT. A magistrate's override returns the complaint to whichever status it had before the referral. The full transition table is on the fir-registry page.
What the citizen sees on the Track screen for each status:
| Ledger status | Citizen app label |
|---|---|
| (on the phone, not yet sent) | Waiting to send |
FILED | Received |
UNDER_ENQUIRY | Preliminary enquiry |
ENQUIRY_CLOSED | Enquiry closed |
NCR_RECORDED | Non-cognizable report |
REGISTERED | FIR registered (Under review while a magistrate looks at a probable duplicate) |
REFERRED | With magistrate |
UNDER_INVESTIGATION | Under investigation |
CLOSURE_REPORT_FILED | Closure report filed |
CHARGESHEET_FILED | Chargesheet filed |
IN_COURT | In court |
DISPOSED | Case closed |
QUASHED | Quashed |
LINKED | Linked to a case |
Sources: digifir-chaincode docs/SPEC.md sections 3.2 to 3.9, 4.2 and 5.2; digifir-backend docs/architecture/ARCHITECTURE.md section 5 and DECISIONS.md ADR-15; citizen and police apps, assets/i18n/en.json and lib/screens/home/widgets/format.dart on the migration branch.