lookup_court_case
Look up a North Carolina (NC) court case or traffic citation.
Provide a case number (e.g. "26CV001234-012"), a citation number
(e.g. "92403H2"), OR a `portalSessionRef` from a `search_cases_by_party` row.
`caseNumber` is the STABLE, canonical identifier — prefer it for anything that
isn't an immediate follow-up. `portalSessionRef` is a fast path that resolves an
already-searched case without re-running the portal search. Its lifetime is
UNSPECIFIED and not guaranteed — the value rotates on every search and should be
treated as short-lived (it survives at least minutes; the upper bound is unmeasured);
never persist or reuse it. (`caseHash` is accepted as a deprecated alias for
`portalSessionRef`.)
Returns case status, upcoming and recently-elapsed hearing dates/times/
locations, charges (including speed fields for traffic cases), and — for
traffic charges — whether each charge is waivable or requires a court
appearance under the NC AOC schedules, plus how to request a reduction or
dismissal (online via NC Guide & File when the county participates, else in
person via the District Attorney) in `citationOptions.howToRequest`. Those are
OPTIONS WITH CONSEQUENCES, NOT A RECOMMENDATION: waiving is a guilty plea to the
charge as written (an admission of responsibility on an infraction), while a
reduction changes the charge before any plea, and both have to be completed BEFORE
THE CASE IS CALLED — not merely on or before the court date. Present them as choices,
not advice; `citationOptions.notice` carries this caveat verbatim.
`citationOptions.state` IS THE RESOLUTION PATH AND OUTRANKS THE PER-CHARGE CLASSES.
Two of its values turn on the clock, and both forbid "no appearance needed" no matter
how many charges read `waivable`: "lastDay" (the hearing is TODAY — settleable with
the clerk only before the case is called, no time to file online) and "noCourtDate"
(no upcoming hearing, or today's has already been called — do not assert a failure to
appear, since the person may have attended that morning). Relay `howToRequest`
verbatim and it will be right for every state.
Read-only: no email is sent and nothing is saved. North Carolina only.
Informational, not legal advice.
EVERY LOOKUP ENDS WITH TWO THINGS, PER CASE. Both are spelled out in
`present_to_user`, the FIRST key of this result, already filled in for this
particular case — read it and do what it says.
(1) `caseSummaryUrl` — hand it to the user and call it the durable, shareable link
to the full case record. It does not expire, it is publicly viewable, and the same
case returns the same link every time, so it is the canonical way to cite or share
the case. THE KEY IS ALWAYS PRESENT, so "when it appears" is not the test — the
VALUE is: non-null means give it; null means minting failed on this lookup, so say
nothing about a link rather than substituting `trackThisCase.url`, a portal URL, or
a guess.
(2) `alerts` — when `alerts.available` is true, ask whether they'd like email alerts
when the case changes: a new court date, case information, case events, service
events, or financial updates. ASK and wait for a yes. Never call
`subscribe_to_case_updates` on your own initiative and never invent an email address.
When `available` is false the case is closed, disposed, or not found — nothing would
ever be sent — and you must not raise it.
IN A MULTI-CASE TURN DO BOTH FOR EACH CASE, beside that case's own details. Two
cases means two links and two offers; one combined link, or a single offer at the
end of the answer, is wrong.
(A search row's `portal_url` is ephemeral by contrast — don't present that as
durable or persist it.)
`upcomingHearings` lists only FUTURE hearings; `pastHearings` lists recently-
elapsed ones (most recent first). The top-level `status` of "no_upcoming_hearings"
means exactly that — NOT that the case has no hearing history. Before telling the
user they have no court date, check `pastHearings`: an empty `upcomingHearings`
with a non-empty `pastHearings` means a hearing has ALREADY occurred (they may
have missed it) — a different answer than "nothing scheduled." Never infer "you
didn't miss court" from an empty `upcomingHearings`/`status` alone.
`service` answers "was the defendant actually reached?" on civil / SP / estate cases
— the civil-side counterpart to `bailRisk`, and null on criminal/traffic, where
service of process does not apply (null there = NOT APPLICABLE, not "not served").
Read `status` FIRST; three of its values mean the absence of a return is EXPECTED and
must never be reported as "not served":
- `served` / `unserved` / `mixed` — a return of service is docketed. `mixed` means
both outcomes appear (several defendants, or the alias-and-pluries retry cycle).
- `proven_other` — a certificate / affidavit / acceptance of service instead of a
formal return. Still proof.
- `appeared_service_moot` — the defendant answered or appeared, which waives a
service defect. Service became unnecessary.
- `not_required` — an appeal or petition; no summons is issued at all.
- `pending` — a summons went out recently and nothing is back YET. Say "service is
still outstanding", NOT "they weren't served".
- `unknown` — a summons issued, nothing returned, and the case isn't new.
`returns[]` is the full history (the retry cycle is often the story) and
`latestReturn` the most recent attempt. `returns[].party` is NULL about a third of
the time — the docket records the outcome without naming who it applied to — so
never read a null party as "nobody". For the same reason there is deliberately NO
per-defendant served flag: one case in the sample had a single docketed return
against 41 defendants, and a per-party boolean would be confidently wrong.
`legacyScan:true` means the paper file was scanned as ONE bundle rather than itemised,
so proof of service may sit inside that PDF where no docket-text rule can see it —
a missing return is weak evidence on those cases.
`causesOfAction` is the civil counterpart to `charges` — the claims pleaded
(`cause`, `filedOn`, `remedy`), e.g. "CV - Unfair Trade Practice". On a civil / SP /
estate case this is usually the ONLY statement of what the matter is about, so lead
with it there. An empty list means the docket does not ITEMISE causes, NOT that no
claims exist — say the docket doesn't break them out rather than implying the case is
about nothing. Repeated boilerplate entries are collapsed; distinct dates are kept,
since a cause added later is an amendment.
Each charge also carries `offenseDate` (when the offense occurred — different from the
case's `filedOn`, and usually what someone means by "when was this?") and `agency`
(the citing law-enforcement agency).
If a tool returns an `error` with `retryable` / `upstream_status`, that is a transport
or portal failure — NOT a statement about the case. Never turn it into "no results" or
"case not found"; say the lookup itself failed, and retry only when `retryable` is
true.
`caseCategory` normalizes the case class (criminal | civil | infraction |
special_proceeding | estate | juvenile | other). Use it to read null fields
correctly: on a NON-criminal category, `bailRisk`/`citationOptions` = null means
NOT APPLICABLE, not "none found." `parties` is the register-of-actions roster
(name + roles[] + attorneys[]{name, appointment} + selfRepresented + counselWaived)
— `appointment` is how counsel came to the case ("Retained" = the party hired them,
vs "Court Appointed" / "Public Defender"; null when unstated, and the list is learned
from the register rather than a closed set). It is what makes a `counselWaived:true`
party who nonetheless HAS counsel intelligible — appointed, then a waiver, then
retained. The authoritative
source for identifying who is on a case and their role, especially on civil/SP cases
where the caption/DOB are absent; prefer it over a party-search row's caption for
entity resolution. `selfRepresented:true` = no counsel of record (self-listed as own
attorney OR a filtered counsel-absence sentinel, with no other attorney); it does
NOT distinguish an active pro-se appearance from a defaulted / served-by-publication
defendant. `counselWaived` is a SEPARATE, independent flag — NOT a narrowing of
`selfRepresented` — and it is NOT a claim the party is unrepresented: it can be true
while attorneys[] is non-empty (seen on 22CR702455-520, counselWaived:true with a
Court Appointed AND a Retained attorney, the docket running appointed counsel ->
Waiver of Counsel -> retained counsel). Always read it WITH attorneys[], never
instead of it. `counselWaived` is set by either
Odyssey placeholder "attorney" name, filtered out of attorneys[] rather than shown
as a lawyer: "WAIVED, WAIVED" (counsel affirmatively waived on the record — the
docket does not say whether the waiver covered all assistance of counsel or only
court-appointed counsel) or "PRO SE" (the party asserted as their own
representation). Either means the party declined counsel rather than merely lacking
it, but the flag does NOT say which placeholder produced it, so it is not proof the
party is litigating pro se. `counselWaived:false` means NOT OBSERVED, not "did not
waive". A true value is predominantly a criminal-side artifact and is rare on civil
rosters — treat it as unexpected but NOT impossible on a non-criminal `caseCategory`;
don't read one there as an error. A false unrepresented party is still any of
defaulted / never-served / unappeared-entity / pro-se-without-a-docketed-marker —
or simply TOO EARLY: on a recently-filed case that has not had a hearing yet,
counsel is frequently not entered on the roster. `parties` reflects what is
DOCKETED, not who is retained; check `filedOn` and an empty `pastHearings` before
reading an empty attorneys[] as unrepresented — on a pending case that has not
been to court, "not shown yet" is usually the better answer than "no lawyer."
attorneys[] non-empty ⇒ represented ⇒ selfRepresented false.
`documents` lists scanned filings, newest first — `{date, name, url}`, where `name` is
the register entry that produced it ("Bond Forfeiture Notice", "Release Order Issued",
"Waiver of Counsel"). Most criminal cases have at least one; an empty list means
nothing is scanned in, not that nothing was filed. Offer the links when they're
relevant to what was asked. Retrieval is UNRELIABLE — the portal intermittently
returns errors or an empty body while it prepares a document — so present a link as
something that may need a retry, never as "here is the document", and never state or
guess at its contents: this server does not read them.
`dispositions` gives the per-charge OUTCOME behind a "Disposed" status — one row per
charge with `plea`, `disposition`, `sentence`, `dispositionDate`, `judge`, and any
judgment `documentUrls`. This is how you answer "what happened to the case / to a
charge": a "Disposed" caseStatus alone does not say whether a charge was dismissed,
pled down, or convicted — read `dispositions` for that (e.g. a speeding charge reduced
to improper equipment shows plea "Responsible to Lesser"; a "VD-District Dismissals ...
Per Plea Agreement" is a dismissal). Empty on pending/undisposed cases.
`trackThisCase` is an upstream ELIGIBILITY FLAG (non-null only on an open case), not
something to act on: this server already consumes it — it is what gates
`alerts.available` — so don't reason from it, and never show `trackThisCase.url` to
the user. That is a generic signup page with no case identity. The case-specific
paths are `caseSummaryUrl` and, once the user has said yes, `subscribe_to_case_updates`.
For criminal cases with a bond or bail activity, `bailRisk` is non-null:
failure-to-appear history (`ftaCount`, date-deduped; `ftaEvents[]` gives the raw
counted entries {date, description} for auditing — voided "in Error/Stricken" FTAs
are already excluded), FTA-triggered `ordersForArrest`, bond amount/type,
and the NCGS §15A-544.5(f) prior-FTA bar. That bar turns on FTAs that preceded the
bond's EXECUTION, not the case total: `bondExecutedOn` is the "Bond Posted" date for
the operative bond and `priorFtasAtExecution` counts FTAs strictly before it (null
when no posting is docketed).
- `setAsideBarInapplicable:true` (0-1 prior FTAs) is RELIABLE — (f) cannot bar a
set-aside. State it plainly; it's the answer that tells someone a motion is
worth filing.
- `setAsideBarPossible:true` (2+ prior) is NOT a finding that the bar applies. It
means only that the TIMING fits. Under (f), actual notice exists ONLY where a
judicial official noted the prior failures on the defendant's release order.
Check `releaseOrderFBox` below before saying anything further, and never say
"the forfeiture cannot be set aside" on the strength of this flag alone.
- Both false = execution date unknown; neither ruled out nor suggested.
`releaseOrderUrl` is the portal PDF of the release order governing that bond — the
document the (f) question actually turns on, since the judicial official's "second or
subsequent failure to appear" notation appears there (AOC-CR-200) and in NO structured
field. ALWAYS present this link when `setAsideBarPossible` is true, even when the read
below already answered the question: the order is the authority.
`releaseOrderFBox` IS THAT READ, present only on barred cases where the order could be
fetched and parsed. Report it, and report it precisely — this is the field that decides
whether someone spends their one motion:
- "unchecked" — on its face (f) does NOT bar a set-aside; the prior FTAs do not block
relief and it is worth pursuing. Say so, and add that they should confirm it on the
order before relying on it.
- "checked" — (f) MAY bar it. Do NOT say "cannot be set aside". Tell them to confirm
on the order BEFORE filing, because a motion that fails uses up the single
opportunity for relief.
- "ambiguous" — the order was opened and the box could NOT be read. Say exactly that,
and hand over the link. The notation is a flattened checkbox with no glyph in the
text layer, so the printed label appears whether or not it is marked. NEVER round
this to "unchecked": a misread tells a bondsman to abandon a recoverable bond.
- absent / null — no read was attempted (not a barred case, no order docketed, or the
fetch failed). This is ALSO not "unchecked". Fall back to the link.
For the forward-looking question ("could a bond I write NOW be barred?") use
`ftaCount`: 2+ FTAs on the case means the next release order should carry the
judicial notation — tell the user to read it before signing.
Then `forfeiture` with its `status`
(the latest DOCKETED forfeiture event — may lag the clock) and the 150-day set-aside
clock (`noticedOn`, `deadline`, `daysRemaining`, `windowOpen`). `noticeAnchor` says
where `noticedOn` came from: "notice_event" = an explicit forfeiture NOTICE line
(the date the statute runs the 150 days from); "earliest_forfeiture_event" = no
notice was docketed, so the earliest forfeiture entry stands in — the deadline is
then a CONSERVATIVE proxy (earlier than the true notice), and `daysFtaToNotice`
measures FTA-to-forfeiture rather than FTA-to-notice. Don't present a proxy-anchored
deadline as the exact statutory date — treat `windowOpen`/`daysRemaining`
as authoritative for whether the set-aside window is open; once `windowOpen` is false
the window has closed even if `status` still reads `in_effect`.
`deadlineNextBusinessDay` is the first day the clerk's office is open on or after
`deadline` (equal to it when that is already a business day; later when it falls on
a weekend or NC court holiday). ADVISORY ONLY — it never moves `daysRemaining` /
`windowOpen`, which stay on the strict notice+150 date, because the safe error is
telling someone they have LESS time, never more. null = UNDETERMINED (deadline year
outside the published NC holiday calendar), NOT "no adjustment needed"; never
present a null as though the deadline is a normal business day.
`triggeringFta` (latest counted FTA on or before `noticedOn`) and `daysFtaToNotice`
(the gap in days) report HOW LONG after the failure the forfeiture notice was
docketed. Report the number; do NOT call a long gap a defect or a filing error —
there is deliberately no threshold flag, and whether a gap affects the notice's
validity is for the reader's attorney. Plus the bonding
`agent` (Fiduciary) + `surety` (insurer). All from public NC eCourts records.
(`citationOptions` is null on disposed/closed cases — the reduction path isn't live.)
Informational underwriting signal, not legal advice; don't state legal conclusions.