# retrieve-IQ API documentation > retrieve-IQ tracks and checks property tax bills for firms and their clients: it fetches bills from the counties, checks the figures, and keeps payment and appeal dates. It never pays a bill. Its GraphQL API and MCP server give a firm's own systems and AI assistants the same data the app shows. These pages explain how to connect, walk through the common tasks, and list every query, mutation and type with the scope each needs. # Getting started > Everything the app shows is open to your own systems: parcels, tax bills and their checks, payment and appeal deadlines, documents and reports. This guide explains how to connect; the reference lists every query, mutation and type. ## Overview The API is GraphQL over HTTPS at one endpoint. Every request is a `POST` with a JSON body and an API key in the `Authorization` header, and every answer is JSON. ```http POST https://api.retrieveiq.net/graphql ``` Each request sees your firm's own data and nothing else. retrieve-IQ tracks and checks bills; it never pays them, and nothing in the API moves money. Bills are fetched from the counties retrieve-IQ covers, which the app's Coverage screen and the [coverage](/docs/queries.md#coverage) query list by state, on a schedule retrieve-IQ sets for each firm: every parcel is read again at least weekly. California is the first state open. A parcel in a county not yet covered is tracked with its deadlines, and its bills arrive once the county is. Call the API from a server or a script. A browser may call it only from the retrieve-IQ app's own origin, so a web page of your own cannot reach it directly. - [Common tasks](/docs/recipes.md): loading parcels, reading bills, reviewing them, deadlines and appeals, reports. - [Keeping in sync](/docs/sync.md): a nightly read of what changed, and the file feed. - [AI assistants](/docs/assistants.md): the same data over the Model Context Protocol. - [Changes](/docs/changes.md): what the API promises about change, and what has changed. ## API keys A person at your firm creates a key in the app under **Settings, API keys, New key**: a name that says what it is for, the scopes it may use, and optionally the last day it works. - The key starts with `riq_` and is shown once. Store it where your system will read it; only a hash is kept, and it cannot be shown again. - A key acts as your firm, limited to the scopes you gave it. It can never hold `ADMIN` and cannot create other keys. - Revoke a key on the same screen. A revoked or expired key is refused at once, with a message that says which; a calendar feed it created stops answering, and a report it requested that has not run yet fails. - Send it as a bearer token: `Authorization: Bearer riq_...` ## Your first request Ask who the key acts as and how many parcels it can see (the key needs `PARCEL_READ`): **curl** ```bash curl https://api.retrieveiq.net/graphql \ -H "Authorization: Bearer $RETRIEVEIQ_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"{ viewer { name tenant { name } } parcels(first: 5) { totalCount edges { node { id parcelNumber } } } }"}' ``` **Node.js** ```javascript const response = await fetch('https://api.retrieveiq.net/graphql', { method: 'POST', headers: { Authorization: `Bearer ${process.env.RETRIEVEIQ_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ query: "{ viewer { name tenant { name } } parcels(first: 5) { totalCount edges { node { id parcelNumber } } } }" }), }); const { data, errors } = await response.json(); ``` **Python** ```python import json import os import urllib.request request = urllib.request.Request( "https://api.retrieveiq.net/graphql", data=json.dumps({"query": "{ viewer { name tenant { name } } parcels(first: 5) { totalCount edges { node { id parcelNumber } } } }"}).encode(), headers={ "Authorization": f"Bearer {os.environ['RETRIEVEIQ_API_KEY']}", "Content-Type": "application/json", }, ) with urllib.request.urlopen(request) as response: payload = json.load(response) # payload["data"], and payload.get("errors") ``` The answer is a JSON object with `data`, and an `errors` list when something was refused (see [Errors](#errors)). Any GraphQL client works; there is nothing to install. Every response carries an `x-request-id` header; quote it when you write to support about a request. ```json { "data": { "viewer": { "name": "Nightly loader", "tenant": { "name": "Example Tax Advisors" } }, "parcels": { "totalCount": 0, "edges": [] } } } ``` A firm's own portfolio is usually empty, as here: its parcels belong to its clients. The next section names one. ## Acting for a client A tax firm holds no property of its own; it works for clients under an engagement. List the clients your key may act for, then name one on each request with the `X-Engagement-ID` header (this request needs `REPORT_READ`): ```graphql { myEngagements { engagementId live client { name } scopes } } ``` ```bash curl https://api.retrieveiq.net/graphql \ -H "Authorization: Bearer $RETRIEVEIQ_API_KEY" \ -H "X-Engagement-ID: $ENGAGEMENT_ID" \ -H "Content-Type: application/json" \ -d '{"query":"{ portfolioSummary { parcelCount } }"}' ``` - Without the header, a firm's key sees the firm's own portfolio, which for most firms is empty. - Under an engagement the key may do what both the key's scopes and the engagement's scopes allow. - An engagement that has ended is refused with `FORBIDDEN`, never answered with an empty list, so a lapsed client cannot be mistaken for one with no data. - Never send `X-Tenant-ID`, `X-Actor-Tenant-ID`, `X-User-ID` or `X-Scopes`. Who you are is derived from the key, and a request carrying any of them is refused with a 400. ## Scopes A key holds one or more of 6 data scopes, and a person signed in to the app holds all of them. | Scope | Allows | | --- | --- | | `APPEAL_WRITE` | Record appeals and update them. | | `BILL_READ` | Read tax bills, the checks run against them, the documents behind them and the nightly fetch status. | | `BILL_REVIEW` | Accept, flag and reject bills, resolve their checks, and take a decision back. | | `PARCEL_READ` | Read parcels, their assessments, the units that assess and bill them, deadlines and calendar feeds. | | `PARCEL_WRITE` | Add and import parcels. | | `REPORT_READ` | Request and download reports, and read the portfolio summary. | Every entry in the reference says which scope it needs, and the [types](/docs/types.md) say which scope reading them needs wherever they are reached from: `portfolioSummary` needs `REPORT_READ`, and a parcel's `bills` field needs `BILL_READ` even though the parcel itself needs `PARCEL_READ`. A write scope does not include the matching read scope, so each mutation's entry names both: a review needs `BILL_REVIEW` and `BILL_READ`, an appeal `APPEAL_WRITE` and `PARCEL_READ`. A key holding only the write scope is refused when it reads the result, and because any error undoes the whole request, nothing is written. Reading the inbox and the fetch status (`inboxSummary`, `billInbox`, `ingestionStatus`) needs `PARCEL_READ` beside `BILL_READ`. Give a key the least it needs; a nightly export needs only the read scopes. ## Conventions - Ids are opaque strings. Keep them as they are given; never build or parse one. - `Date` is a calendar date, `YYYY-MM-DD`, with no time and no timezone. `DateTime` is an instant in ISO 8601, UTC. - `Money` is a decimal string in dollars with two places, `"71486.32"`, so no precision is lost on the way. A figure the county does not publish is `null`, never `0`. - A record you may not see and a record that does not exist look the same: `null`, or absence from a list. The API does not say which. - Property tax has two years. `assessmentYear` is the year a value was set, which an appeal contests; `payableYear` is the year the bill falls due. Which comes first depends on the county. - The schema is open to introspection with your key, and the SDL is at [/docs/schema.graphql](/docs/schema.graphql) for a client that generates code from it. ## Paging Long lists (`parcels`, `billInbox`) are connections. Ask for a page with `first` (25 when omitted, at most 100), then pass the last `endCursor` as `after` while `hasNextPage` is true. Lists page forward only: `last` and `before` are accepted and ignored. A cursor belongs to the filter it was cut under; a cursor presented with another filter is refused with `INVALID_CURSOR`. ```graphql query ($after: String) { parcels(first: 100, after: $after) { totalCount pageInfo { hasNextPage endCursor } edges { node { id parcelNumber situsAddress { line1 city state } } } } } ``` ## Documents and reports Files are not inside GraphQL responses. A `Document` carries a `contentPath` and a finished `ReportJob` a `downloadUrl`. Fetch either with a plain `GET`, the same `Authorization` header and, for a client's files, the same `X-Engagement-ID`: ```bash curl -OJ https://api.retrieveiq.net/documents//content \ -H "Authorization: Bearer $RETRIEVEIQ_API_KEY" ``` Where a header cannot be sent (a new browser tab, an embedded viewer), [createDocumentLink](/docs/mutations.md#createdocumentlink) gives a path that opens one document without it, for five minutes, checked again when it is opened. A document goes the other way through an upload link; [Common tasks](/docs/recipes.md#upload-a-document) shows both steps. Reports are made in the background: `requestReport` queues one, and `reportJobs` shows when it is `DONE` and where to fetch it. Both routes answer with the file and a `Content-Disposition` header naming it, or with a small JSON body and one of these statuses: | Status | Body | Meaning | | --- | --- | --- | | 401 | `{"reason": "unauthenticated"}` | No valid key. The document route writes the reason in capitals. | | 403 | `{"reason": "NOT_ENTITLED"}` | The key lacks `BILL_READ` (documents) or `REPORT_READ` (reports), or the engagement does not allow it. | | 404 | `{"reason": "not_found"}` | No such file, or one you may not read. The two are not told apart. | | 404 | `{"reason": "bytes_unavailable"}` | The record exists but the bytes are not held. For a document, `sourceUrl` names the county page the bill was read from. | | 410 | `{"reason": "file_removed"}` | A document removed by the retention rule, seven years after it was fetched or uploaded; the message says when. What was read from it stays. | | 503 | `{"reason": "documents_unavailable"}` | The document is held but cannot be opened on the server at the moment. Try again later; it is not a fault in your request. | | 429 | `{"reason": "rate_limited"}` | Too many requests; wait the seconds in `Retry-After`. | ## Errors A refusal comes back in `errors`, each with `extensions.code` to switch on and a message written to be read by a person. A request refused on its credentials (no bearer token, a key that is unknown, revoked or expired), on its rate or on a forbidden header also carries a matching HTTP status; everything else is a 200 whose `errors` carry the code. Switch on `extensions.code`, not on the status. | Code | Status | Meaning | | --- | --- | --- | | `UNAUTHENTICATED` | 401 | No bearer token, one that is not a key, or a key that is unknown, revoked or expired; the message says which. | | `RATE_LIMITED` | 429 | Too many requests. Wait the seconds in the `Retry-After` header. | | `BAD_USER_INPUT` | 400 or 200 | A forbidden header (400); otherwise an input that is wrong, or a query that asks for too much at once (`extensions.reason` is `QUERY_DEPTH`, `QUERY_BREADTH` or `QUERY_COMPLEXITY`). | | `FORBIDDEN` | 200 | Refused on who you are. `extensions.reason` says which: `NOT_ENTITLED` (the key or the engagement lacks the scope, or the engagement is not yours), `ENGAGEMENT_LAPSED` (it has ended or not started), `INVALID_ENGAGEMENT` (the header is not an engagement id), `NOT_A_PERSON` (keys are managed by people, not by another key), `NOT_OWN_FIRM` (keys are managed from your own firm, not under an engagement). | | `CONFLICT` | 200 | The change collides with what is already recorded, such as a second appeal for the same year, or the bill or appeal changed after the version you read (`extensions.reason` is `STALE_VERSION`): read it again and decide on what it says now. | | `UNRESOLVED_VALIDATIONS` | 200 | A bill cannot be accepted while an error-level check stands against it; `extensions.codes` lists them. | | `UNDO_REFUSED` | 200 | A review decision cannot be taken back. `extensions.reason` is `NO_DECISION`, `ALREADY_UNDONE`, `NOT_YOURS` (only the person who decided can), `EXPIRED` (older than 10 minutes) or `CHANGED` (the bill moved since). | | `INVALID_CURSOR` | 200 | A paging cursor from another filter or another list. | | `AUTH_UNAVAILABLE` | 503 | The service cannot verify credentials at the moment. Retry with a backoff; it is not a fault in your request. | A query GraphQL itself cannot accept (an unknown field, a missing variable) is a 200 whose `errors` carry `GRAPHQL_VALIDATION_FAILED` and the position of the fault; a request that sends `Accept: application/graphql-response+json` gets it as a 400. ## Limits - **600 requests a minute per key**, refilling continuously, so a steady loader never meets the limit and a short burst is absorbed. Past it, a 429 with `Retry-After`. Downloads count against the same limit. - **Query size:** at most 8 levels deep, 250 fields, and a cost of 5,000 where a list counts ten times what it holds. Every screen of the app fits well inside; a query that asks for everything does not. Page through lists instead. Every example in this documentation is held under these limits with each release. - **Imports:** `importParcels` takes up to 500 rows a call, and `importPayments` up to 2,000. ## AI assistants The same data is offered to assistants that speak the Model Context Protocol, at `https://api.retrieveiq.net/mcp`, with the same key as the bearer token, under the same scopes and engagements as the GraphQL API. [AI assistants](/docs/assistants.md) lists its tools and how to connect one. This documentation is also written for assistants to read: [/llms.txt](/llms.txt) indexes every page, and each page is available as Markdown at its address with `.md` added. The **Copy page** button at the top of each page copies that Markdown. ## Glossary - **Parcel**: one property as the county assesses it, with a parcel number. What the portfolio counts. - **Taxing unit**: the office that assesses a parcel or sends its bill; a county in California, a county, township or school district elsewhere. The reference calls it a `Jurisdiction`. - **Tax account**: one parcel's billing relationship with one unit, under the number the unit uses. A parcel billed by three units has three. - **Bill** and **installment**: a bill is one year's tax from one unit on one account, paid in installments, each with its own due date. A payment posted or interest grown updates the bill in place; a re-issue with other charges, or a person's correction, is its next **revision**, waiting for review. - **Check**: a comparison run against a bill as it arrives (the parcel number, the year, a jump from last year). The reference calls it a `Validation`; its `severity` says whether it blocks acceptance. - **Withheld**: a bill with an unresolved `ERROR` check. Its figures are shown for review and left out of every total until the check is resolved or the bill rejected. - **Owner of record**: the entity the parcel is held under, as the client registered it. The reference calls it a `LegalEntity`. - **Engagement**: a client's standing arrangement for your firm to act on its portfolio, with its own scopes and dates. - **Scope**: one of the permissions a key holds; see [Scopes](#scopes). - **Deadline**: a payment or appeal date derived from a bill and the unit's rules. One the rules cannot date is still listed, with the reason. - **Assessment year** and **payable year**: see [Conventions](#conventions). # Common tasks > The things a firm's own system does against the API, each as a short walk with the exact operations to send. Every example here validates against the schema with each release. ## Before you start Every example below is sent the way [Your first request](/docs.md#your-first-request) shows, with an API key and, when the portfolio is a client's, the `X-Engagement-ID` header from [Acting for a client](/docs.md#acting-for-a-client). Ids are passed as variables; literal values are made up. ## Load a portfolio A parcel belongs to an owner of record and to the unit that assesses it. List the owners the portfolio already holds, and find the unit by state and name (needs `PARCEL_READ`): ```graphql { legalEntities { id name } jurisdictions(state: "CA", search: "Los Angeles") { id name unitCode installmentsPerYear } } ``` Add one parcel with [upsertParcel](/docs/mutations.md#upsertparcel) (needs `PARCEL_WRITE`, and `PARCEL_READ` to read the parcel back). Naming the county is enough in California; `jurisdictionId` names the unit directly elsewhere. Repeating the call is safe: a parcel already held comes back with `created: false` and nothing changed. ```graphql mutation ($owner: ID!) { upsertParcel(input: { parcelNumber: "5144-012-023" county: "Los Angeles" legalEntityId: $owner situs: { line1: "350 S Grand Ave", city: "Los Angeles", state: "CA", postalCode: "90071" } }) { created parcel { id parcelNumber status jurisdiction { name } } } } ``` Add a spreadsheet of parcels with [importParcels](/docs/mutations.md#importparcels), up to 500 rows a call. Run it with `dryRun: true` first: every row is checked and nothing is written, and `rejected` names each bad row by its index. Then send the same call without `dryRun`. An owner is named once for the whole call, by id or by a name that is created when it is new. ```graphql mutation { importParcels(input: { dryRun: true legalEntityName: "Grand Avenue Holdings LLC" rows: [ { parcelNumber: "5144-012-023", county: "Los Angeles", situsLine1: "350 S Grand Ave", city: "Los Angeles", zip: "90071" } { parcelNumber: "5149-034-010", county: "Los Angeles" } ] }) { dryRun created existing rejected { index reason } } } ``` ## Read bills and their checks A parcel's bills arrive from the fetch, newest year first. Each bill carries its installments, the checks run against it, the charges the county levied and the document it was read from (needs `PARCEL_READ` and `BILL_READ`): ```graphql query ($id: ID!) { parcel(id: $id) { parcelNumber status amountOutstanding { known installmentCount installmentsWithUnknownPayment withheldCount } bills(last: 6) { key assessmentYear payableYear billType billNumber revision version status totalBilled withheld withheldReason installments { id installmentNo installmentLabel dueDate delinquentAfter amountDue amountPaid paymentKnown amountOutstanding status } validations { id code severity message expected observed resolvedAt } charges { description amount chargeType levyingAgency agencyPhone } sourceDocument { id filename contentPath receivedAt } } } } ``` - `withheld: true` means an `ERROR` check stands: the figures are shown here and left out of every total until a person resolves the check or rejects the bill. - `amountPaid` is what the county publishes; `paymentKnown: false` means it publishes nothing, which is not the same as nothing paid. - `charges` describe the whole bill and sum to `totalBilled`, never to one installment. `levyingAgency` and `agencyPhone` are the office to ask about a line. - `revision` counts the bill's issues. When the unit re-issues it with other charges, or a person corrects a reading, the new figures are the next revision, under a `key` of their own and waiting for review, and the revision they replace reads `SUPERSEDED` or `REJECTED` and counts nowhere. A payment posted or interest grown updates the same revision. - `version` moves with every change to the bill, its figures and its decisions alike; a review decision names it (below). - The document's bytes are a `GET` of `https://api.retrieveiq.net` followed by its `contentPath`, with the same headers. What is outstanding across the portfolio, and by county (needs `PARCEL_READ` and `BILL_READ`): ```graphql { amountOutstanding { known installmentCount installmentsWithUnknownPayment withheldCount } countiesInPortfolio { jurisdiction { name state } parcelCount amountOutstanding { known withheldCount } } } ``` ## Upload a document A bill that reached you on paper or by email, or any other document about a parcel, can be filed on the parcel (needs `BILL_REVIEW`). Start the upload with [startDocumentUpload](/docs/mutations.md#startdocumentupload), naming the parcel, what the document is, its file name and its exact size. The answer is a link for the bytes, good once, for fifteen minutes: ```graphql mutation ($parcelId: ID!) { startDocumentUpload(input: { parcelId: $parcelId, kind: TAX_BILL, filename: "2026-secured-bill.pdf", byteSize: 182344 }) { uploadPath method expiresAt maxBytes } } ``` Then send the file to that path with a `PUT` and the same `Authorization` header. The link already names the portfolio the upload was started under, so it needs no `X-Engagement-ID`: ```bash curl -X PUT "https://api.retrieveiq.net$UPLOAD_PATH" \ -H "Authorization: Bearer $RETRIEVEIQ_API_KEY" \ --data-binary @2026-secured-bill.pdf ``` - A PDF, CSV or Excel (`.xlsx`) file, no larger than `maxBytes`. Scans and photos are not read. - A bill PDF from a county whose bills the product reads exactly is read as a bill, which waits for review like a fetched one; anything else is kept on the parcel as evidence. The answer, a 201, names the document and says what became of the reading. - The same file already on the parcel is that document, and the answer, a 200, says so; the same file on another parcel is refused with a 409 that names it, and a bill printed for another parcel with a 422. - A link already used or past its fifteen minutes answers 410: start again. Uploaded files are kept for seven years. ## Review bills A fetched bill waits for a decision. The inbox lists the ones waiting, oldest first; decide per bill by naming its installment ids (needs `BILL_READ` and `PARCEL_READ` to read the inbox, and `BILL_REVIEW` as well to decide): ```graphql query ($after: String) { inboxSummary { needsReview disputed withheld receivedThisWeek } billInbox(first: 25, after: $after, filter: { view: WAITING }) { totalCount pageInfo { hasNextPage endCursor } edges { node { key version status withheld totalBilled parcel { id parcelNumber } taxAccount { jurisdiction { name } accountNumber } installments { id installmentLabel amountDue dueDate status } validations { id code severity message resolvedAt } } } } } ``` Accept a bill whose figures are right, naming every installment of the bill. Refused with `UNRESOLVED_VALIDATIONS` while an `ERROR` check stands against it: ```graphql mutation ($installmentIds: [ID!]!, $version: Int!) { acceptBill(installmentIds: $installmentIds, expectedVersion: $version, note: "Matches the county's figures") { bill { key version status installments { id status } } notVisible } } ``` Every decision names, as `expectedVersion`, the bill's `version` as you read it. When anything about the bill changed since (a fetch, a check resolved, another person's decision), the decision is refused with `CONFLICT` (`extensions.reason` is `STALE_VERSION`) and nothing is written: read the bill again and decide on what it says now. Flag a bill for the client when a person on their side should look first. The note is what the client reads: ```graphql mutation ($installmentIds: [ID!]!, $version: Int!) { flagBillForClient(installmentIds: $installmentIds, expectedVersion: $version, note: "The land value rose 40 percent; please confirm before we accept.") { bill { key version status } notVisible } } ``` Reject a bill that was read wrongly. Rejection is final, apart from the undo below, and a later fetch does not reopen the bill; a re-issue with other charges is the bill's next revision, waiting for review: ```graphql mutation ($installmentIds: [ID!]!, $version: Int!) { rejectBill(installmentIds: $installmentIds, expectedVersion: $version, reason: "Wrong parcel: the county page showed a neighbouring APN.") { bill { key version status } notVisible } } ``` Resolve a check when the discrepancy is explained. The note is required because the next reader asks why, and the bill is no longer withheld once no check stands. Resolving moves the bill's `version`: ```graphql mutation ($id: ID!) { resolveValidation(id: $id, note: "The supplemental bill explains the jump; confirmed with the assessor.") { validation { id code resolvedAt } bill { key version withheld status } } } ``` Take back your own decision within 10 minutes with [undoBillReview](/docs/mutations.md#undobillreview), naming the `version` the decision's answer carried; each installment returns to what it was, and both the decision and its undoing stay in the activity trail: ```graphql mutation ($installmentIds: [ID!]!, $version: Int!) { undoBillReview(installmentIds: $installmentIds, expectedVersion: $version) { bill { key version status installments { id status } } notVisible } } ``` `notVisible` lists the ids you named that the request could not act on, so a partial result is never silent; a response that also carries an error means the whole request was undone. Every decision is recorded against the parcel with who made it and when; `activity` on the parcel reads the trail. When a reading is wrong and you have the right figures, [correctBill](/docs/mutations.md#correctbill) records them as the bill's next revision, checked like any reading and waiting for review, and keeps the one it replaces as evidence. A tax bill page that no reading turned into a bill is entered by hand with [enterBill](/docs/mutations.md#enterbill). ## Record what was paid What a county publishes as paid is on each installment. Your own records go beside it, never into it: record a payment, a refund or a signed adjustment against an installment (needs `BILL_REVIEW` and `BILL_READ`). The same entry sent twice is one entry: ```graphql mutation ($installmentId: ID!) { recordPayment(installmentId: $installmentId, kind: PAYMENT, amount: "35743.16", effectiveDate: "2026-12-08", reference: "Check 10482") { recorded installment { id amountPaid paymentKnown paidPerRecords payments { kind amount effectiveDate reference } } } } ``` Or a whole list at once with [importPayments](/docs/mutations.md#importpayments), up to 2,000 rows a call, each naming its parcel, year and installment (needs `BILL_REVIEW` and `PARCEL_READ`). Run it with `dryRun: true` first. A row whose number matches no parcel exactly comes back in `rejected` with the parcels it may mean, to send again with `parcelId`: ```graphql mutation { importPayments(input: { dryRun: true rows: [ { parcelNumber: "5144-012-023", assessmentYear: 2026, installmentNo: 1, amount: "35743.16", paidOn: "2026-12-08", reference: "Check 10482" } { parcelNumber: "5149-034-010", assessmentYear: 2026, installmentNo: 1, amount: "12210.40", paidOn: "2026-12-09" } ] }) { dryRun recorded alreadyRecorded rejected { index reason } } } ``` `paidPerRecords` on an installment, and `installmentsPaidPerRecords` on every outstanding total, say what your records show paid where the county has published no payment. They are never subtracted from what is owed, since the county has not confirmed them. ## Deadlines, appeals and the calendar Payment and appeal dates across the whole portfolio, soonest first (needs `PARCEL_READ`; `exposure`, the balance at stake on a payment, is bill data and needs `BILL_READ` as well). Pass `from` and `to` on a large portfolio, which otherwise lists every date to come. A date the rules cannot work out is listed with `on: null` and the reason, never dropped; a parcel with no bill yet has no appeal dates. A unit's own appeal window belongs to no parcel, and is listed once with `parcel: null`: ```graphql query ($from: Date!, $to: Date!) { deadlines(from: $from, to: $to) { kind on exposure qualifier unevaluableReason parcel { id parcelNumber } jurisdiction { name } } } ``` Record an appeal of one assessment year (needs `APPEAL_WRITE` and `PARCEL_READ`). The filing deadline comes from the unit's own window unless `deadlineOn` is given; `CONFLICT` means the year already has one: ```graphql mutation ($parcelId: ID!) { openAppeal(parcelId: $parcelId, assessmentYear: 2026, requestedValue: "18500000.00", note: "Comparable sales support a lower value.") { id version status deadlineOn deadlineReason assessedValue requestedValue } } ``` File it once it is lodged, and record the decision when it comes, with the savings if known; once decided, only the appeal's note can change. Each names, as `expectedVersion`, the appeal's `version` as you read it, and is refused with `CONFLICT` when the appeal changed since: ```graphql mutation ($appealId: ID!, $version: Int!) { updateAppealStatus(appealId: $appealId, expectedVersion: $version, action: FILE, filedOn: "2026-11-20") { id version status filedOn } } ``` ```graphql mutation ($appealId: ID!, $version: Int!) { recordAppealOutcome(appealId: $appealId, expectedVersion: $version, decidedOn: "2027-03-02", decidedValue: "19200000.00", savings: "9400.00") { id version status decidedValue valueReduction savings } } ``` While the appeal is open or filed, [updateAppeal](/docs/mutations.md#updateappeal) changes the value it asks for or when its window closes; its note can change at any status: ```graphql mutation ($appealId: ID!, $version: Int!) { updateAppeal(appealId: $appealId, expectedVersion: $version, requestedValue: "18000000.00", note: "Lowered after the second appraisal.") { id version requestedValue deadlineOn note } } ``` A person who has dealt with a date marks it with [acknowledgeDeadline](/docs/mutations.md#acknowledgedeadline) (needs `BILL_REVIEW`). A date that later moves comes back unacknowledged, with `supersedes` saying what it was. For a calendar application, create a subscribable iCal URL over the whole portfolio's dates (needs `PARCEL_READ`; each payment carries the balance at stake when the key also holds `BILL_READ`). The URL carries its own secret and is shown once; it answers until it is revoked with [revokeCalendarFeed](/docs/mutations.md#revokecalendarfeed), or until the key that made it is revoked or expires: ```graphql mutation { createCalendarFeed(label: "Outlook") { url feed { id label createdAt } } } ``` ## Reports The catalogue lists each report with its columns, the formats it comes in and the scopes it reads with (any key): ```graphql { reportCatalog { kind name category description formats columns scopes } } ``` Request one (needs `REPORT_READ` and the scopes the catalogue lists for it). It is produced in the background with the access of the request that asked for it, the engagement's scopes capped by the key's, checked again when it runs; the filter takes the parcel list's conditions apart from the assessed value: ```graphql mutation { requestReport(kind: DEADLINE_EXPOSURE_REGISTER, format: XLSX, filter: { states: ["CA"] }) { id status name } } ``` The appeal evidence pack (`APPEAL_EVIDENCE_PACK`) is made for one appeal or a few by naming them in the filter's `appealIds`; as a `ZIP` it holds the documents themselves beside the pack. [rerunReport](/docs/mutations.md#rerunreport) asks again for a report that failed or expired, as it was asked. Poll the jobs until `status` is `DONE`, then fetch `downloadUrl` with a `GET` and the same headers: ```graphql { reportJobs(first: 5) { id kind format status requestedAt finishedAt rowCount byteSize downloadUrl error } } ``` ```bash curl -OJ https://api.retrieveiq.net/reports//download \ -H "Authorization: Bearer $RETRIEVEIQ_API_KEY" \ -H "X-Engagement-ID: $ENGAGEMENT_ID" ``` ## Watch the nightly fetch Which counties answered last night and which are failing, per county the portfolio holds parcels in, and the client's last nights of the file feed where one is set up (needs `BILL_READ` and `PARCEL_READ`, under the client's engagement): ```graphql { ingestionStatus { jurisdiction { name } parcels lastAttemptAt lastAnsweredAt lastSuccessAt lastOutcome streak } feedRuns(last: 7) { id feedName startedAt finishedAt outcome deliveredTo message } } ``` A county with a `streak` of failures has usually changed its website; `lastOutcome` says how it failed. Your bills from that county stand as last fetched until it answers again. # Keeping in sync > Two ways to follow the portfolio as the nightly fetch moves it: read it again through the API each morning, or take the file feed retrieve-IQ delivers to you. ## What moves overnight Each night retrieve-IQ fetches bills from the units on the schedule set for your firm: every parcel is read again at least weekly, and one whose last fetch failed is tried again the next night. The checks run on what was read and the deadlines follow. A new bill arrives as `NEEDS_REVIEW`. A bill whose payment, dates or interest the unit has changed is brought up to date in place, under the same `key`, with its checks run again, whatever was decided about it. A bill the unit re-issues with other charges (on a page that lists none, another total) is the bill's next `revision`, under a key of its own and waiting for review, and the revision it replaces reads `SUPERSEDED` and counts nowhere; a rejected bill stays rejected. A unit that did not answer leaves its bills as they were. Appeals and owners change only when a person or your system changes them; a parcel's current assessment follows what the unit publishes, and the fetch fills in a blank street line from the unit's record. ## Reading the portfolio again There is no "changed since" filter in the API yet, so a system that mirrors the portfolio reads it in full each morning and compares. Read it in two steps, so that each request stays inside the [limits](/docs.md#limits). First the parcels, 100 a page in parcel-number order, each with its six newest bills and their headline figures (needs `PARCEL_READ` and `BILL_READ`); a portfolio of ten thousand parcels is a hundred requests: ```graphql query ($after: String) { parcels(first: 100, after: $after, orderBy: { field: PARCEL_NUMBER, direction: ASC }) { pageInfo { hasNextPage endCursor } edges { node { id parcelNumber status legalEntity { id name } jurisdiction { id name state unitCode } currentAssessment { assessmentYear totalValue } bills { key status withheld totalBilled amountOutstanding { known installmentsWithUnknownPayment } } } } } } ``` Then, for each parcel whose bills moved, the installments: ```graphql query ($id: ID!) { parcel(id: $id) { bills { key status withheld installments { id installmentLabel dueDate amountDue amountPaid paymentKnown amountOutstanding status } } } } ``` A page of the first query costs 865 of the 5,000 a request may spend, and the second 842; the tests hold both there with each release. - Key parcels on `id` and bills on `key`, which is stable across requests. A bill's payment and dates can change under the same key: compare `status`, `withheld`, `totalBilled` and `amountOutstanding` with what you hold, and read the installments of the bills that differ. A re-issue is a new key, the bill's next `revision`, and the one it replaced reads `SUPERSEDED`. - Read in the morning, Pacific time: the fetch runs overnight and the checks follow it. - A parcel is never dropped from the list: one that was sold or is exempt says so in its `status`. - A bill with `withheld: true` shows `null` for `totalBilled` and `amountOutstanding` until a person resolves the check that holds it; its installments still carry their figures. ## The file feed For a system that would rather load files than call an API, retrieve-IQ can deliver the whole portfolio each night as a set of files: to an SFTP server (a user on it whose authorised keys include the public key retrieve-IQ gives you, the path to write under, and the server's host key fingerprint, which is pinned), to an S3 bucket or an S3-compatible store (the bucket, a prefix, and credentials that may write under it), or to a folder on a host retrieve-IQ runs. The feed is set up for your firm on request. Each night's files land in a folder named for the date, `YYYY-MM-DD` in UTC, under the path you gave; `manifest.json` is written last, so a folder with a manifest is complete and one without is still being written or was abandoned. Once the feed runs, [feedRuns](/docs/queries.md#feedruns) shows each client's nights and where the files went, read under that client's engagement. A delivery is four files, every client of the firm together: - `bills.csv`: one row per installment of every bill, with the client named on each row. - `line_items.csv`: one row per charge on a bill, joined to `bills.csv` by `tax_bill_id`. - `feed.xlsx`: the same two tables as the sheets "Bills" and "Line items", money as numbers. - `manifest.json`: written last; the night's id, the schema version (`3`), each file's row count, byte size and SHA-256 so a partial upload is caught before it is loaded, each client's row count, the night's fetch summary per client, and the readings withheld since the feed last ran: pages fetched that could not be read as a bill, each named by parcel and unit with the year, the bill type and the reason, so a bill that is missing is missing on purpose. A bill recorded with a check standing is in the file, not here. The CSVs are RFC 4180: UTF-8 without a byte order mark, CRLF records, a field quoted only when it holds a comma, a quote or a line break. Money is dollars with two decimals as text (`71486.32`); an unknown figure is an empty cell, never `0`. Booleans are `true` and `false`. Every bill retrieve-IQ holds is in the file, a rejected one and one a failed check holds back included, with their amounts empty and `figures_withheld` saying so, so a column summed never adds a figure that failed a check. The files are the whole portfolio every night, not the changes, and `fetched_at` moves whenever an account's bills are read again, so two nights' files rarely match byte for byte: compare rows on the other columns to see whether a figure moved. Within each client, rows are ordered by state, county, unit, parcel number, assessment year, bill type, bill number, revision and installment, so one unit's rows are contiguous; the clients follow one another. A parcel billed by more than one unit is more than one row per installment, each naming its unit and account; in California it is one. A client whose fetch failed that night is left out of the files rather than delivered as empty, and its night in `feedRuns` says so (`SWEEP_FAILED`); the other clients' rows are delivered. When the files could not be produced or delivered, no client gets them, and every client's night names the stage that failed. ## bills.csv Sum amounts per row. Count properties, and sum `assessed_value`, by distinct `parcel_id`. | Columns | Meaning | | --- | --- | | `client_tenant_id`, `client_name` | The client the row belongs to; every client of the firm is in the one file. | | `parcel_id` | The parcel, one property; stable across nights. The feed's ids are retrieve-IQ's own and differ in form from the API's, so match a row to the API on `parcel_number` and `jurisdiction_code`, not on id. | | `county`, `state` | The billing unit's county, as registered (`Los Angeles County`), and its state, two letters. | | `jurisdiction`, `jurisdiction_level`, `jurisdiction_code`, `jurisdiction_id` | The unit that sent the bill: its name, its level (`county`, `city`, `township`, `school_district` and so on), its stable code to key a per-unit table on, and retrieve-IQ's own id for it. | | `tax_account_id`, `account_number` | The billing relationship the bill belongs to, and the unit's own number for the property under it (the APN in California). | | `fiscal_year_label` | The year label the unit's calendar gives the bill, where one is recorded; empty otherwise, never guessed. | | `parcel_number`, `situs_line1`, `legal_entity` | The parcel number as the assessing unit knows it, the property's street line when known, and the owner of record as registered. | | `assessment_year`, `payable_year` | The year of the roll the bill is for, and the year it is payable in. | | `bill_type`, `bill_number`, `revision` | `SECURED`, `UNSECURED`, `SUPPLEMENTAL`, `ESCAPE` or `REDEMPTION`; the unit's own number, empty where it publishes none; `0` for the bill as the unit first issued it, and the next number for a re-issue with other charges or a person's correction. Only the newest revision of each bill is written. | | `installment_no`, `installment_label` | Which installment of the bill the row is (1, 2, ...) and what the unit calls it. | | `amount_due`, `amount_paid`, `payment_known` | The amount on the installment; what the unit reports paid, empty when it publishes no figure; `true` when `amount_paid` is a figure. Zero paid and unknown are different facts. All three are empty on a row whose figures are withheld (below). | | `penalty`, `penalty_basis` | The penalty the unit states and whether it is `included_in_amount_due` or `added_to_amount_due`; both empty when none is stated. | | `amount_outstanding` | `amount_due`, plus the penalty when it is added, minus `amount_paid`; empty when a side of that sum is unknown. | | `due_date`, `delinquent_after` | When the installment is payable and the last day before it costs more. | | `review_status` | The bill's state in review, in lower case: `needs_review`, `validated`, `disputed` or `rejected`; `ingested` is reserved. A rejected bill's rows are in the file with their figures withheld. | | `validation_warnings` | The codes of the checks still standing against the bill, separated by `;`, on the row of the bill's first installment and empty on the others. Warnings and errors are listed alike; a check a person resolved, or one a later fetch found passing, is not listed. | | `assessed_value` | The newest assessment held for the parcel and the assessment year. The parcel's figure, repeated on every row of the parcel: never sum it across rows. | | `source_url`, `fetched_at`, `as_of` | Where the bill was read from, when the account was last fetched successfully (which moves whenever its bills are read again), and the date the unit's page stated. | | `tax_bill_id` | The row's id: the join key to `line_items.csv`, which joins to the row of the bill's first installment. | | `figures_withheld`, `withheld_reason` | `true` on every row of a bill that a failed check holds back or a reviewer rejected, whose `amount_due`, `amount_paid`, `payment_known`, `penalty` and `amount_outstanding` are then empty, so a column summed never adds a figure that failed a check; `withheld_reason` says why (`rejected by a reviewer`, or `a check failed:` and the checks). `false` and empty otherwise. | ## line_items.csv One row per charge on a bill. The charges describe the whole bill and sum to its installments together, not to the row they join. | Columns | Meaning | | --- | --- | | `tax_bill_id`, `tax_account_id`, `jurisdiction_code` | The bill row the charge belongs to (the row of the bill's first installment), with its account and unit repeated so the file joins without the other. | | `parcel_number`, `assessment_year`, `bill_type`, `bill_number` | The bill's key, repeated for a reader that has only this file. | | `ordinal` | The charge's position on the bill. | | `description`, `amount` | The charge as printed; the amount is signed, so a refund is negative. | | `charge_type` | `ad_valorem`, `voter_approved_debt`, `direct_charge`, `special_assessment`, `penalty_and_cost` or `fee`; empty when the bill's own sectioning does not say, never guessed. | | `rate`, `code` | The rate and the unit's code for the charge, when printed. | | `levying_agency`, `agency_phone` | Who levies the charge and the phone number printed beside it. | | `figures_withheld`, `withheld_reason` | As on the bill's rows: when the bill's figures are withheld, `amount` is empty, so the charges never add up to what the bill holds back. | # AI assistants > The same portfolio, offered to assistants that speak the Model Context Protocol: Claude, and any client that connects to an MCP server over HTTP. ## The MCP server retrieve-IQ serves the Model Context Protocol over HTTP at one address. An assistant connected to it can list your clients, summarise a portfolio, list deadlines, find a parcel and open its detail, explain a bill line by line, and report the nightly fetch, under the same scopes and engagements as the GraphQL API. Every tool only reads; none changes a record. ```http https://api.retrieveiq.net/mcp ``` - Authenticate with an API key as the bearer token, exactly as for GraphQL. A key with `PARCEL_READ`, `BILL_READ` and `REPORT_READ` can use every tool; each tool's entry below names the scopes it needs. - Where retrieve-IQ has enabled it for your deployment, a person's own sign-in works too: the server publishes the discovery documents an MCP client needs to send the person through retrieve-IQ's sign-in. Until then, use a key. - The assistant names the client it acts for by passing the engagement id `list_clients` returns to the other tools as `engagement`. A firm owns no property itself, so a tool called without one answers from an empty portfolio. ## Connecting Claude In Claude Code, add the server once with its key: ```bash claude mcp add --transport http retrieve-iq https://api.retrieveiq.net/mcp \ --header "Authorization: Bearer $RETRIEVEIQ_API_KEY" ``` Or in a `.mcp.json` checked in beside a project, with the key read from the environment: ```json { "mcpServers": { "retrieve-iq": { "type": "http", "url": "https://api.retrieveiq.net/mcp", "headers": { "Authorization": "Bearer ${RETRIEVEIQ_API_KEY}" } } } } ``` Any other client that connects to a remote MCP server over HTTP takes the same address and the same header. Then ask in plain words: "what is due in the next thirty days for Grand Avenue Holdings", "why is this bill higher than last year", "which counties did not answer last night". ## Tools What the server offers, as it lists them to a client, each with the scopes its own query needs. Every tool is read-only. A tool answers with the same figures the app shows and says when a date could not be worked out (`unevaluableReason`); `find_parcel` says when its list is cut short (`hasMore`), `parcel_detail` holds the six newest assessments and bills, and `explain_bill` looks among the twelve newest bills. ### explain_bill `tool`, needs `BILL_READ` and `PARCEL_READ` Breaks one tax bill into the charges the county actually levied, with the agency behind each line and its phone number where the bill prints one. Use this for "why am I being charged this" questions. The levying agency is frequently not the county, and the phone number is on the bill precisely because that agency expects to be asked about that line: pass it on rather than summarising it away. Charges describe the whole tax year and sum to totalBilled, never to one installment. Looks among the parcel's twelve newest bills. Inputs: - `engagement` (`string`): Engagement id from list_clients. - `parcelId` (`string!`, required): The parcelId returned by find_parcel. - `billKey` (`string!`, required): The billKey returned by parcel_detail. ### find_parcel `tool`, needs `PARCEL_READ` Search the portfolio by parcel number or address (street or city). Returns one page plus totalCount and hasMore. When hasMore is true say so rather than implying the list is complete. Inputs: - `engagement` (`string`): Engagement id from list_clients. - `search` (`string`): Free text matched against parcel number and situs address. - `limit` (`integer`): Default 20, max 50. ### ingestion_status `tool`, needs `BILL_READ` Which counties the nightly fetch is failing in and which answered last night, per California county this portfolio holds parcels in, plus the last nights of the feed. A county with a streak has probably changed its portal; lastOutcome says how it failed. Pass the engagement id when acting for a client. Inputs: - `engagement` (`string`): Engagement id from list_clients. Omit when acting for yourself. ### list_clients `tool`, any key Lists the clients you may act for, with the engagement id every other tool takes. Call this first when acting for a firm: a firm owns no property itself, so omitting the engagement returns an empty portfolio rather than an error. A client shown as live: false has lapsed and its data is no longer readable. ### list_deadlines `tool`, needs `BILL_READ` and `PARCEL_READ` Payment and appeal dates across the portfolio, soonest first. Entries the rules cannot date are returned with on: null and a plain-English unevaluableReason, rather than omitted. Report those as unknown dates and give the reason: a deadline that cannot be derived is not a deadline that does not exist, and the difference matters to a taxpayer. An entry with scope "jurisdiction" is a unit's own appeal window, which belongs to no parcel: its parcelNumber and situs are null. Inputs: - `engagement` (`string`): Engagement id from list_clients. - `from` (`string`): ISO date, inclusive lower bound. - `to` (`string`): ISO date, inclusive upper bound. ### parcel_detail `tool`, needs `BILL_READ` and `PARCEL_READ` Everything held for one parcel: its six newest assessments and bills, what is owed and the next payment. One call rather than several, so do not follow it with find_parcel for the same property. Use the billKey it returns with explain_bill. Inputs: - `engagement` (`string`): Engagement id from list_clients. - `parcelId` (`string!`, required): The parcelId returned by find_parcel. ### portfolio_summary `tool`, needs `BILL_READ`, `PARCEL_READ` and `REPORT_READ` What is owed across the portfolio and where. Counties come first because the work of property tax scales with the number of counties, not the number of properties. Pass an engagement to act for a client; omit it to act for yourself. Amounts are decimal strings in major units, and null means the figure is unknown, never that it is zero. installmentsWithUnknownPayment is how incomplete the owed figure is: report it when it is above zero rather than presenting the total as complete. installmentsPaidPerRecords is how many of those the customer's own records show paid: say it beside the figure and never subtract it, since the county has not confirmed them. legalEntities is the same portfolio by owner: each entity with its parcels, their assessed value (the newest assessment of each active parcel, the rule assessedValue uses) and what is owed on their bills. Inputs: - `engagement` (`string`): Engagement id from list_clients. Omit when acting for yourself. ## Reading this documentation These pages are written for assistants as well as people: [/llms.txt](/llms.txt) indexes every page, each page is available as Markdown at its address with `.md` added, and [/llms-full.txt](/llms-full.txt) holds all of it in one file. The schema itself is at [/docs/schema.graphql](/docs/schema.graphql). The **Copy page** button at the top of each page copies that Markdown, and its menu opens the page in Claude or ChatGPT. # Changes > What the API promises about change, and what has changed, newest first. ## What you can rely on - Changes are additive. A new field, argument, enum value or operation can appear at any time; a query you wrote keeps working. - Nothing is removed without notice. A field or argument that is going away is marked deprecated in the schema, with the reason and what to use instead, and stays for at least six months after that. - A new enum value can appear in a field you already read. Handle a value you do not know as "other" rather than failing. - Error codes and `extensions.reason` values are part of the contract; a new reason can appear, an existing one is not renamed. - The Markdown pages and `llms.txt` follow the same rules, so an assistant that learned the API keeps its footing. Deprecations appear in the reference as a tag on the field, and here with their date. ## Not in the API yet What this documentation does not promise, because the product does not do it yet. Each will appear above, dated, when it lands. - A "changed since" filter. A system that mirrors the portfolio reads it in full, as [Keeping in sync](/docs/sync.md) shows. - An assessment's own revisions. Every assessment is revision 0, and a value read again replaces the figure on the same one. - The `INGESTED` bill status, the `QUEUED`, `OCR_RUNNING`, `MATCH_FAILED` and `CONFIRMED` extraction states, and the `MAILED_PDF`, `EMAIL`, `SFTP_FEED` and `UPLOAD` ways a unit makes its bill available: in the schema, recorded for no unit and set by nothing today. Handle them as "other". ## 16 October 2026 - Two changes need a change to your calls. Every review decision and every change to an appeal now names the version it was made from: `acceptBill`, `flagBillForClient`, `rejectBill` and `undoBillReview` take `expectedVersion`, the bill's `version` as you read it, and `updateAppealStatus` and `recordAppealOutcome` take the appeal's. When the bill or the appeal changed after you read it, the call is refused with `CONFLICT` (`extensions.reason` is `STALE_VERSION`) and nothing is written. And `Deadline.parcel` can be null: a unit's own appeal window, which belongs to no parcel, is listed once with its unit. - A bill the unit re-issues with other charges (on a page that lists none, another total) is the bill's next `revision`, under a `key` of its own and waiting for review; the revision it replaces reads `SUPERSEDED`, a new status, and counts nowhere. A payment posted or interest grown still updates the bill in place. `correctBill` records a person's correction of a reading as the next revision, checked like any reading, and `enterBill` enters a bill by hand from a tax bill page no reading turned into one. - Documents: `startDocumentUpload` gives a link, good once for fifteen minutes, to `PUT` a PDF, CSV or Excel file to; a bill PDF from a county the product reads exactly is read as a bill, and anything else is kept on the parcel as evidence. `createDocumentLink` gives a five-minute path that opens a document without a header. A document is kept seven years; after that its route answers 410 `file_removed`, and one that cannot be opened at the moment answers 503 `documents_unavailable`. - Your own payment records: `recordPayment` and `importPayments` (up to 2,000 rows a call, with `dryRun`) record payments, refunds and adjustments beside the county's figures, never into them. `TaxBillInstallment.payments` and `paidPerRecords`, `TaxBill.paidPerRecords`, `Deadline.paidPerRecords` and `OutstandingTotal.installmentsPaidPerRecords` say what they show. - Bills: `annualTotal`, `chargesTotal`, `installmentsTotal` and `penaltyIncluded` give the county's stated total, the charges and the installments apart. `PAID` and `CLOSED` are deprecated and never returned: a status is the review state alone, and what is paid is `amountPaid` and `paymentKnown`, from the county, and `payments` and `paidPerRecords`, from your records. `Validation.resolutionNote` and `Validation.history` keep who resolved each check and why; `Extraction.fields` and `pages` say where each figure was printed. - Dates are kept: `Deadline.id` names one, `acknowledgeDeadline` marks it handled, and `supersedes` says what a moved date was. `deadlineGeneration` says when the dates were last worked out. `Deadline.paidPerRecords` needs `BILL_READ`, as `exposure` does. - Appeals: `updateAppeal` changes what an open or filed appeal asks for and when its window closes, and its note at any status; `Appeal.version` and `ruleDeadlineOn` are new. The evidence pack (`APPEAL_EVIDENCE_PACK`) is made for named appeals with `ReportFilter.appealIds`, and as a `ZIP` holds the documents themselves. `rerunReport` asks again for a report that failed or expired. - Owners and units: `legalEntitiesInPortfolio` breaks the portfolio down by owner of record; `setLegalEntityTaxId` and `clearLegalEntityTaxId` keep an owner's tax identification number encrypted and show only `taxIdLast4`. `assessingJurisdictions`, `Jurisdiction.rules` and `Jurisdiction.appealRequirements` give each unit's dated rules with their evidence and what an appeal there needs; `reportRule` and `ruleReports` tell retrieve-IQ a rule looks wrong and show what became of it. `ParcelInput.state` and `ParcelImportRowInput.state` name a county outside California. - Engagements: the record says when the client approved it, under what reference and by whom, and when it was revoked and why. Revoking one stops your access the moment it is recorded; a report or an upload under way at that moment is not kept, and its message says so. - The file feed is version 3: a bill a failed check holds back, or one a reviewer rejected, keeps its rows with its amounts empty, `figures_withheld` true and `withheld_reason` saying why, and its charges likewise; `validation_warnings` lists only the checks still standing. ## 14 October 2026 - Every operation's entry names every scope it needs. A change that returns a record needs the scope to read it as well as the scope to make it: `acceptBill` needs `BILL_REVIEW` and `BILL_READ`, `upsertParcel` needs `PARCEL_WRITE` and `PARCEL_READ`, `openAppeal` needs `APPEAL_WRITE` and `PARCEL_READ`. `ingestionStatus`, `billInbox`, `inboxSummary` and `portfolioSummary` need `PARCEL_READ` beside their own scope. Each MCP tool's entry names its scopes. - A key's scopes hold wherever its work runs: a report is produced with the engagement's scopes capped by the key's, `requestReport` refuses a key or an engagement without the scopes a report reads with (`reportCatalog` lists them as `scopes`), and a queued report fails if that access ends before it runs. `Deadline.exposure`, the balance at stake on a payment, needs `BILL_READ`; the dates still need only `PARCEL_READ`, and a calendar feed made without `BILL_READ` carries the dates alone. - Revoking a key ends what it made: a calendar feed it created answers 403 from then on, and a report it requested that has not run yet fails. An unknown, revoked or expired key answers 401, as a missing token does; switch on `extensions.code` all the same. - `deadlines` and the calendar feed cover the whole portfolio; the first 500 parcels by parcel number was the earlier limit. `portfolioSummary` is computed from the portfolio as it stands when it is read. - `jurisdictions` asks for a state, a level or a search, takes `level` and `first` (500 when omitted, up to 5,000), and answers in state and name order. `team` lists the people who can sign in, to a person signed in to the app and not to a key. `acceptBill` refuses a bill with an error-level check standing on any of its installments, not only the ones named. `countiesInPortfolio` breaks a tie on the amount owed by name. `upsertParcel` and `importParcels` refuse the state's own name as a county. `ReportJob.error` is a sentence for the person who asked, not a note for the operator. `Portal` no longer carries the survey's own notes, rule codes and reader codes. - The examples select only what their scopes allow, and the Keeping in sync read is two queries, each held under the [limits](/docs.md#limits); the earlier one did not fit. - Descriptions say what is reserved rather than what is planned: every bill and assessment is `revision` 0 and a fetch refreshes it in place; `INGESTED`, `PAID` and `CLOSED` are set by nothing today; a rejected bill is not reopened by a later fetch; a decided appeal cannot be changed. - The file feed as it is written: `fetched_at` moves whenever an account is read again, so two nights rarely match byte for byte; `validation_warnings` sits on the bill's first installment row and lists the checks no person has resolved, cleared ones included; `line_items.csv` joins to that same row; a client whose fetch failed is left out of the files; the feed's ids differ in form from the API's. - The Python first request uses the standard library only. ## 13 October 2026 - This documentation: every query, mutation, type, field and argument described, the scope each operation needs on its entry, an example for each operation, and the tool list of the MCP server. - Common tasks, Keeping in sync and AI assistants pages added. - The schema is served at `/docs/schema.graphql`. # Queries > Every read the API answers, in alphabetical order, with what each takes and returns, the scope it needs and an example to send. ### activeEngagement `query`, returns [`Engagement`](/docs/types.md#engagement), any key The engagement named by the X-Engagement-ID header. Null when the request acts as your own firm. Example: ```graphql { activeEngagement { id approvalRecorded authorisationRef authorisedOn effectiveFrom effectiveTo engagementId grantedBy client { id name kind } agent { id name kind } } } ``` ### amountOutstanding `query`, returns [`OutstandingTotal!`](/docs/types.md#outstandingtotal), needs `BILL_READ` What is still owed across the whole portfolio, and how complete that figure is. Example: ```graphql { amountOutstanding { installmentCount installmentsPaidPerRecords installmentsWithUnknownPayment known withheldCount } } ``` ### apiKeys `query`, returns [`[ApiKey!]!`](/docs/types.md#apikey), signed-in people only Your firm's API keys, the ones that work first. Always the firm's own, whichever client you are acting for. For people signed in to the app; a request made with a key is refused. Example: ```graphql { apiKeys { id name status createdAt expiresAt lastUsedAt prefix revokedAt } } ``` ### assessingJurisdictions `query`, returns [`[Jurisdiction!]!`](/docs/types.md#jurisdiction), needs `PARCEL_READ` The units that assess this portfolio's parcels, where its appeals are filed, by state then name. Example: ```graphql { assessingJurisdictions { id name assesses billDelivery bills fipsCode installmentsPerYear kind } } ``` ### bill `query`, returns [`TaxBill`](/docs/types.md#taxbill), needs `BILL_READ` The bill one of its installments belongs to. A bill has no id of its own, so pass the id of any of its installments. Null when the installment is not visible to you, which is also what one that does not exist returns. Arguments: - `id` (`ID!`, required): The id of one of the bill's installments. Example: ```graphql query ($id: ID!) { bill(id: $id) { key status annualTotal assessmentYear billNumber billType chargesTotal installmentsTotal acceptedAutomatically { at reason } amountOutstanding { installmentCount installmentsPaidPerRecords installmentsWithUnknownPayment known withheldCount } } } ``` ### billInbox `query`, returns [`BillConnection!`](/docs/types.md#billconnection), needs `BILL_READ` The bills waiting on a decision (NEEDS_REVIEW or DISPUTED), the oldest arrival first and the undated last; or, with view DECIDED, the ones a person accepted or rejected, newest arrival first with the undated ahead of them. One record per bill. Needs PARCEL_READ as well as BILL_READ. A cursor belongs to the filter it was cut under. Arguments: - `after` (`String`): The cursor to continue from: the endCursor of the page before. - `before` (`String`): Not supported: lists page forward only, with first and after. - `filter` ([`BillInboxFilter`](/docs/types.md#billinboxfilter)): Which bills. The waiting ones when omitted. - `first` (`Int`): How many records to return: 25 when omitted, at most 100. - `last` (`Int`): Not supported: lists page forward only, with first and after. Example: ```graphql { billInbox(first: 25) { totalCount pageInfo { hasNextPage endCursor } edges { node { key status annualTotal assessmentYear billNumber } } } } ``` ### calendarFeeds `query`, returns [`[CalendarFeed!]!`](/docs/types.md#calendarfeed), needs `PARCEL_READ` The calendar feeds still in force over this portfolio, newest first. Revoked feeds are not listed. Example: ```graphql { calendarFeeds { id createdAt label lastFetchedAt revokedAt createdBy { id name email } } } ``` ### countiesInPortfolio `query`, returns [`[CountyOutstanding!]!`](/docs/types.md#countyoutstanding), needs `PARCEL_READ` Every unit that bills a parcel in the portfolio (a county, a township, a school district), with what is owed to each. Ordered by the amount owed, largest first, then by name. The rows are billing units of any level, under a name kept for compatibility. Example: ```graphql { countiesInPortfolio { parcelCount jurisdiction { id name assesses billDelivery bills } } } ``` ### coverage `query`, returns [`Coverage!`](/docs/types.md#coverage), any key Where bills can be fetched: by state and by county, with the reason where they cannot. The same for every caller. Example: ```graphql { coverage { countyTotals { assessmentOnly closed covered noPortal notSurveyed } totals { assessmentOnly closed covered noPortal notSurveyed } } } ``` ### coverageUnit `query`, returns [`CoverageUnit`](/docs/types.md#coverageunit), any key One unit by its code (US-CA-FIPS-06007), with its sites. Null when the registry does not hold it, and for a state. Arguments: - `unitCode` (`String!`, required): The unit code, as Jurisdiction.unitCode has it. Example: ```graphql query ($unitCode: String!) { coverageUnit(unitCode: $unitCode) { name status assesses bills countyLevel fips level state portals { status discoveredOn host reason url } } } ``` ### deadlineGeneration `query`, returns [`DeadlineGeneration!`](/docs/types.md#deadlinegeneration), needs `PARCEL_READ` When the dates deadlines returns were last worked out, and whether a change saved since is waiting on it. Asked in the same request as deadlines, it answers for the set that request read. Example: ```graphql { deadlineGeneration { generatedAt stale } } ``` ### deadlines `query`, returns [`[Deadline!]!`](/docs/types.md#deadline), needs `PARCEL_READ` Payment and appeal dates across the whole portfolio, soonest first. Dates that could not be worked out come last, with the reason, rather than being hidden. Give from and to for a large portfolio, which otherwise lists every date to come. A parcel with no bill yet has no appeal dates. Arguments: - `from` ([`Date`](/docs/types.md#date)): The first day to include. A date that could not be worked out is listed whatever the range. - `to` ([`Date`](/docs/types.md#date)): The last day to include. A date that could not be worked out is listed whatever the range. Example: ```graphql { deadlines { id acknowledgedAt assessmentYear generatedAt kind on qualifier source parcel { id parcelNumber status useCode } jurisdiction { id name assesses billDelivery bills } } } ``` ### feedRuns `query`, returns [`[FeedRun!]!`](/docs/types.md#feedrun), needs `BILL_READ` The last nights of the feed for the client named by X-Engagement-ID, newest first. Empty without an engagement, or when no feed is set up for the firm. Arguments: - `last` (`Int`, default 7): How many nights: 7 when omitted. Example: ```graphql { feedRuns { id deliveredTo feedName finishedAt message outcome startedAt } } ``` ### inboxSummary `query`, returns [`InboxSummary!`](/docs/types.md#inboxsummary), needs `BILL_READ` The inbox in numbers: what arrived this week, what could not be read, and what waits. Needs PARCEL_READ as well as BILL_READ. Example: ```graphql { inboxSummary { beingChecked disputed failedExtractionsThisWeek needsReview receivedThisWeek withheld } } ``` ### ingestionStatus `query`, returns [`[CountyIngestionStatus!]!`](/docs/types.md#countyingestionstatus), needs `BILL_READ` What the nightly fetch did in each county the portfolio holds parcels in: which answered last night and which are failing. California counties only, for now. Needs PARCEL_READ as well as BILL_READ. Example: ```graphql { ingestionStatus { attempts24h failures24h lastAnsweredAt lastAttemptAt lastOutcome lastSuccessAt parcels streak jurisdiction { id name assesses billDelivery bills } } } ``` ### jurisdictions `query`, returns [`[Jurisdiction!]!`](/docs/types.md#jurisdiction), any key Taxing units from the registry, which is the same for every caller, in state and name order: filter by state, by level, or search by name; at least one is required. At most first are returned (500 when omitted, up to 5,000), so narrow by level or search where a state holds more. An empty list means no unit matched. Arguments: - `first` (`Int`): How many to return at most: 500 when omitted, up to 5,000. - `level` (`String`): The kind of unit, as Jurisdiction.level has it: county, city, town, township, school_district and so on. - `search` (`String`): Part of the name. - `state` (`String`): A two-letter state code. Example: ```graphql { jurisdictions { id name assesses billDelivery bills fipsCode installmentsPerYear kind } } ``` ### legalEntities `query`, returns [`[LegalEntity!]!`](/docs/types.md#legalentity), needs `PARCEL_READ` The owners of record the portfolio holds parcels under, by name. Example: ```graphql { legalEntities { id name taxIdLast4 } } ``` ### legalEntitiesInPortfolio `query`, returns [`[LegalEntityHolding!]!`](/docs/types.md#legalentityholding), needs `PARCEL_READ` Every legal entity that holds a parcel in the portfolio, with how many, their assessed value and what is owed on their bills: the breakdown by owner. Ordered by amount owed, then assessed value, then name. An entity with no parcel is not listed. Example: ```graphql { legalEntitiesInPortfolio { assessedValue assessedValueAsOf parcelCount legalEntity { id name taxIdLast4 } } } ``` ### myEngagements `query`, returns [`[Engagement!]!`](/docs/types.md#engagement), any key Every client engagement your firm holds, the ones in force first. Lapsed engagements are listed too, so a client is not mistaken for a deleted one; a request under one is refused. Example: ```graphql { myEngagements { id approvalRecorded authorisationRef authorisedOn effectiveFrom effectiveTo engagementId grantedBy client { id name kind } agent { id name kind } } } ``` ### node `query`, returns [`Node`](/docs/types.md#node), any key One record by its id, whatever its type. Null with a FORBIDDEN error when your key lacks the scope its type needs; null alone when it is not visible to you or names nothing. Arguments: - `id` (`ID!`, required): The id, as any query returned it. Example: ```graphql query ($id: ID!) { node(id: $id) { __typename id } } ``` ### nodes `query`, returns [`[Node]!`](/docs/types.md#node), any key Several records by id, in the order asked, with null in the place of each that is not visible to you, and a FORBIDDEN error when your key lacks the scope a type needs. Arguments: - `ids` (`[ID!]!`, required): The ids, as any query returned them. Example: ```graphql query ($ids: [ID!]!) { nodes(ids: $ids) { __typename id } } ``` ### parcel `query`, returns [`Parcel`](/docs/types.md#parcel), needs `PARCEL_READ` One parcel: by id, or by parcel number within the unit that assesses it. Pass either id, or parcelNumber with jurisdictionId; anything else is BAD_USER_INPUT. Null when the parcel is not visible to you, which is also what a parcel that does not exist returns. Arguments: - `id` (`ID`): The parcel's id. - `jurisdictionId` (`ID`): The id of the unit that assesses the parcel. With parcelNumber. - `parcelNumber` (`String`): As the county writes it. With jurisdictionId. Example: ```graphql query ($id: ID) { parcel(id: $id) { id parcelNumber status useCode jurisdiction { id name assesses billDelivery bills } situsAddress { city county line1 line2 postalCode } } } ``` ### parcels `query`, returns [`ParcelConnection!`](/docs/types.md#parcelconnection), needs `PARCEL_READ` The parcels you can see, a page at a time: filter and order them, then page with first and after. A cursor belongs to the filter and order it was cut under. Arguments: - `after` (`String`): The cursor to continue from: the endCursor of the page before. - `before` (`String`): Not supported: lists page forward only, with first and after. - `filter` ([`ParcelFilter`](/docs/types.md#parcelfilter)): Which parcels. All of them when omitted. - `first` (`Int`): How many records to return: 25 when omitted, at most 100. - `last` (`Int`): Not supported: lists page forward only, with first and after. - `orderBy` ([`ParcelOrder`](/docs/types.md#parcelorder)): How to order them. Assessed value, highest first, when omitted. Example: ```graphql { parcels(first: 25) { totalCount pageInfo { hasNextPage endCursor } edges { node { id parcelNumber status useCode } } } } ``` ### portfolioSummary `query`, returns [`PortfolioSummary!`](/docs/types.md#portfoliosummary), needs `REPORT_READ` The portfolio in numbers, as it stands now: parcels, the units that bill them, assessed value by state, and what the open appeals might save. Needs PARCEL_READ as well as REPORT_READ. Example: ```graphql { portfolioSummary { assessedValueAsOf jurisdictionCount parcelCount totalAssessedValue appealUpside { appealsWithoutRate basisDecidedAppeals modeled openAppeals realizedRatio } byState { assessedValue parcelCount state } } } ``` ### reportCatalog `query`, returns [`[ReportCatalogEntry!]!`](/docs/types.md#reportcatalogentry), any key The reports that can be produced, with their columns, in the order the app shows them. The same for every caller. Example: ```graphql { reportCatalog { name category columns description formats kind scopes } } ``` ### reportJob `query`, returns [`ReportJob`](/docs/types.md#reportjob), needs `REPORT_READ` One requested report, by id. Null when it is not visible to you. Arguments: - `id` (`ID!`, required): The report job's id, as requestReport returned it. Example: ```graphql query ($id: ID!) { reportJob(id: $id) { id name status byteSize downloadUrl error filterDescription finishedAt requestedBy { id name email } } } ``` ### reportJobs `query`, returns [`[ReportJob!]!`](/docs/types.md#reportjob), needs `REPORT_READ` Reports requested over this portfolio, newest first. Arguments: - `first` (`Int`, default 20): How many: 20 when omitted, at most 100. Example: ```graphql { reportJobs { id name status byteSize downloadUrl error filterDescription finishedAt requestedBy { id name email } } } ``` ### ruleReports `query`, returns [`[RuleReport!]!`](/docs/types.md#rulereport), needs `PARCEL_READ` The reports filed about rules from this portfolio, newest first, up to 100, with each one's status. Example: ```graphql { ruleReports { id status assessmentYear createdAt evidenceUrl problem resolution resolvedAt jurisdiction { id name assesses billDelivery bills } reportedBy { id name email } } } ``` ### search `query`, returns [`SearchResults!`](/docs/types.md#searchresults), needs `PARCEL_READ` Search the portfolio for parcels, units and documents at once. Fewer than two characters returns three empty lists. Arguments: - `first` (`Int`, default 8): How many per list: 8 when omitted, at most 20. - `query` (`String!`, required): What to look for. Example: ```graphql query ($query: String!) { search(query: $query) { parcels { id parcelNumber status useCode } jurisdictions { id name assesses billDelivery bills } } } ``` ### team `query`, returns [`[User!]!`](/docs/types.md#user), signed-in people only The people of your own firm who can sign in, by name. For people signed in to the app; a request made with a key is refused. Example: ```graphql { team { id name email tenant { id name kind } } } ``` ### viewer `query`, returns [`User!`](/docs/types.md#user), any key Who this request acts as: the signed-in person, or the service user the API key stands for. Example: ```graphql { viewer { id name email tenant { id name kind } } } ``` # Mutations > Every change the API makes, with the scopes each needs and an example to send. A change to a parcel, a bill or an appeal is recorded in that parcel's activity trail. An error anywhere in a request undoes the whole request. ### acceptBill `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Accept a bill: NEEDS_REVIEW or DISPUTED becomes VALIDATED, on every installment named or on none. Refused with UNRESOLVED_VALIDATIONS while an ERROR check stands unresolved against any installment of the bill, and with CONFLICT when the bill changed after the version you read (expectedVersion). Name every installment of the bill: its checks are recorded on the first. Arguments: - `expectedVersion` (`Int!`, required): The bill's version as the caller read it (TaxBill.version). If anything about the bill changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `installmentIds` (`[ID!]!`, required): The installments of one bill, from TaxBill.installments. One bill per call. - `note` (`String`): A note for the activity trail. Example: ```graphql mutation ($expectedVersion: Int!, $installmentIds: [ID!]!) { acceptBill(expectedVersion: $expectedVersion, installmentIds: $installmentIds) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### acknowledgeDeadline `mutation`, returns [`Deadline!`](/docs/types.md#deadline), needs `BILL_REVIEW` and `PARCEL_READ` A person marks a saved date as seen and handled. Once per date: a date that later moves is a new date, unacknowledged. BILL_REVIEW, as a decision about a bill; the trail records it with the note. Arguments: - `id` (`ID!`, required): The date, by its Deadline id from deadlines. - `note` (`String`): What was done about it, for the trail. Example: ```graphql mutation ($id: ID!) { acknowledgeDeadline(id: $id) { id acknowledgedAt assessmentYear generatedAt kind on qualifier source parcel { id parcelNumber status useCode } jurisdiction { id name assesses billDelivery bills } } } ``` ### clearLegalEntityTaxId `mutation`, returns [`LegalEntityPayload!`](/docs/types.md#legalentitypayload), needs `ADMIN` and `PARCEL_READ` Remove a legal entity's tax identification number: the encrypted value, its key version and its last four together. The trail records the removal. Arguments: - `legalEntityId` (`ID!`, required): The legal entity, by its id. Example: ```graphql mutation ($legalEntityId: ID!) { clearLegalEntityTaxId(legalEntityId: $legalEntityId) { legalEntity { id name taxIdLast4 } } } ``` ### correctBill `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Correct a reading by hand. The corrected figures become the next revision of the bill, at needs_review like any new reading; the revision they replace is rejected and kept as evidence; the correction is an extraction of its own (engine manual, by the person) and one activity row. Refused before anything is written when the installments do not add up to the charges, so a corrected revision never carries the sum error it was meant to fix. Then checked like any reading (the unit's calendar, the stated total, the prior year): a check that finds an error does not refuse the correction, it withholds the new revision (TaxBill.withheld) until a person resolves the check or corrects the bill again. The checks read the parcel, so an engagement without PARCEL_READ is FORBIDDEN a correction, as it is the inbox. Never an update of a figure in place. Arguments: - `correction` ([`BillCorrectionInput!`](/docs/types.md#billcorrectioninput), required): The figures as the county shows them: each installment by its id, and the charges when they change. - `expectedVersion` (`Int!`, required): The bill's version as the caller read it (TaxBill.version). If anything about the bill changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `note` (`String!`, required): What the county shows, for the trail and the next reader. Example: ```graphql mutation ($correction: BillCorrectionInput!, $expectedVersion: Int!, $note: String!) { correctBill( correction: $correction expectedVersion: $expectedVersion note: $note ) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### createApiKey `mutation`, returns [`ApiKeyCreated!`](/docs/types.md#apikeycreated), signed-in people only Create a key for your own firm. The secret is returned once and never stored. For people signed in to the app: refused while acting for a client, and refused to a request made with a key. Arguments: - `expiresOn` ([`Date`](/docs/types.md#date)): The last day it works, UTC. Omitted, it works until revoked. - `name` (`String!`, required): What it is for, for the list: "Nightly loader". 1 to 80 characters. - `scopes` ([`[Scope!]!`](/docs/types.md#scope), required): One or more of the six data scopes; never ADMIN. Example: ```graphql mutation ($name: String!, $scopes: [Scope!]!) { createApiKey(name: $name, scopes: $scopes) { secret apiKey { id name status createdAt expiresAt } } } ``` ### createCalendarFeed `mutation`, returns [`CalendarFeedCreated!`](/docs/types.md#calendarfeedcreated), needs `PARCEL_READ` Create a subscribable calendar (iCal) URL over the whole portfolio's dates, with the balance at stake on each payment when the request holds BILL_READ. The secret is returned once, inside the URL, and never shown again. The feed answers until it is revoked, or until the key that created it is revoked or expires, or until the engagement it was created under lapses. Arguments: - `label` (`String`): Where it will be used, for the list: "Outlook", "Team calendar". Up to 80 characters; longer is cut. Example: ```graphql mutation { createCalendarFeed { url feed { id createdAt label lastFetchedAt revokedAt } } } ``` ### createDocumentLink `mutation`, returns [`DocumentLink!`](/docs/types.md#documentlink), needs `BILL_READ` A five-minute link to one document's bytes that opens without a header: for a new tab or an embedded viewer. Arguments: - `documentId` (`ID!`, required): The document to open, by its id. Example: ```graphql mutation ($documentId: ID!) { createDocumentLink(documentId: $documentId) { expiresAt path } } ``` ### enterBill `mutation`, returns [`BillEntryPayload!`](/docs/types.md#billentrypayload), needs `BILL_REVIEW` and `BILL_READ` Enter a bill by hand from a tax-bill document no reading turned into a bill. The entry is a reading of its own (engine manual, by the person), checked like any reading, and a bill at needs_review: entering never accepts it. Refused before anything is written when the page is not on this server (it is the entry's evidence), when the parcel already holds a bill of that year and type (correct it from its review), and when the installments do not add up to the charges. Arguments: - `documentId` (`ID!`, required): The tax-bill document the figures are typed from, by its id. - `entry` ([`BillEntryInput!`](/docs/types.md#billentryinput), required): The figures as the page prints them: the year, the bill type, its installments and its charges. - `note` (`String!`, required): What the figures were entered from, for the trail and the reviewer. Example: ```graphql mutation ($documentId: ID!, $entry: BillEntryInput!, $note: String!) { enterBill(documentId: $documentId, entry: $entry, note: $note) { message outcome installments { id status amountDue amountOutstanding amountPaid } } } ``` ### flagBillForClient `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Flag a bill for the client: NEEDS_REVIEW or VALIDATED becomes DISPUTED, on every installment named or on none. The note is what the client reads. Refused with CONFLICT when the bill changed after the version you read (expectedVersion). Arguments: - `expectedVersion` (`Int!`, required): The bill's version as the caller read it (TaxBill.version). If anything about the bill changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `installmentIds` (`[ID!]!`, required): The installments of one bill, from TaxBill.installments. One bill per call. - `note` (`String!`, required): What the client should know. Required. Example: ```graphql mutation ($expectedVersion: Int!, $installmentIds: [ID!]!, $note: String!) { flagBillForClient( expectedVersion: $expectedVersion installmentIds: $installmentIds note: $note ) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### importParcels `mutation`, returns [`ParcelImportPayload!`](/docs/types.md#parcelimportpayload), needs `PARCEL_WRITE` and `PARCEL_READ` Add a whole spreadsheet of parcels at once. Every row is checked before any is written (a blank number, an unknown county, the same parcel twice, more than 500 rows), the accepted rows land together, and rejected rows are reported by index. dryRun checks and writes nothing. California counties only, for now. Arguments: - `input` ([`ParcelImportInput!`](/docs/types.md#parcelimportinput), required): The rows and the owner of record. Example: ```graphql mutation ($input: ParcelImportInput!) { importParcels(input: $input) { created dryRun existing legalEntity { id name taxIdLast4 } rejected { index reason } } } ``` ### importPayments `mutation`, returns [`PaymentImportPayload!`](/docs/types.md#paymentimportpayload), needs `BILL_REVIEW` and `PARCEL_READ` A whole list of the customer's payments at once, each row naming its parcel, year and installment. Every row is checked; the good ones land as one transaction, a row already on record is counted rather than recorded twice, and rejected rows are reported by index with the reason, a row the database refuses among them. dryRun checks and writes nothing. Arguments: - `input` ([`PaymentImportInput!`](/docs/types.md#paymentimportinput), required): The rows, and whether only to check them (dryRun). Example: ```graphql mutation ($input: PaymentImportInput!) { importPayments(input: $input) { alreadyRecorded dryRun recorded rejected { index reason } } } ``` ### openAppeal `mutation`, returns [`Appeal!`](/docs/types.md#appeal), needs `APPEAL_WRITE` and `PARCEL_READ` Record an appeal of one assessment year. The filing deadline comes from the unit's window unless deadlineOn is given; where the window depends on an event whose date is not on record, it stays null with a reason. CONFLICT when the year already has an appeal. Arguments: - `assessmentYear` (`Int!`, required): The year of the assessed value under appeal, 1990 to 2100. - `deadlineOn` ([`Date`](/docs/types.md#date)): The last day to file, when you know it better than the unit's rule. - `note` (`String`): A note for whoever reads the appeal next. - `parcelId` (`ID!`, required): The parcel. - `requestedValue` ([`Money`](/docs/types.md#money)): The value the appeal asks for. Example: ```graphql mutation ($assessmentYear: Int!, $parcelId: ID!) { openAppeal(assessmentYear: $assessmentYear, parcelId: $parcelId) { id status assessedValue assessmentYear createdAt deadlineOn deadlineReason deadlineSource parcel { id parcelNumber status useCode } openedBy { id name email } } } ``` ### recordAppealOutcome `mutation`, returns [`Appeal!`](/docs/types.md#appeal), needs `APPEAL_WRITE` and `PARCEL_READ` Record the decision on an appeal: the date, the value the board set (a value above the assessed value is allowed and recorded), and the tax saved, if known. Final: only the note of a decided appeal can change afterwards (updateAppeal), so record the savings with the decision. Refused with CONFLICT when the appeal changed after the version you read (expectedVersion). Arguments: - `appealId` (`ID!`, required): The appeal. - `decidedOn` ([`Date!`](/docs/types.md#date), required): When it was decided. - `decidedValue` ([`Money!`](/docs/types.md#money), required): The value the board set. - `expectedVersion` (`Int!`, required): The appeal's version as the caller read it (Appeal.version). If the appeal changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `note` (`String`): Replaces the note on the appeal. - `savings` ([`Money`](/docs/types.md#money)): The tax saved, from the corrected bill, if known now; it cannot be added later. Example: ```graphql mutation ($appealId: ID!, $decidedOn: Date!, $decidedValue: Money!, $expectedVersion: Int!) { recordAppealOutcome( appealId: $appealId decidedOn: $decidedOn decidedValue: $decidedValue expectedVersion: $expectedVersion ) { id status assessedValue assessmentYear createdAt deadlineOn deadlineReason deadlineSource parcel { id parcelNumber status useCode } openedBy { id name email } } } ``` ### recordPayment `mutation`, returns [`RecordPaymentPayload!`](/docs/types.md#recordpaymentpayload), needs `BILL_REVIEW` and `BILL_READ` Record one entry in the customer's own payment records for an installment: a payment, a refund, or a signed adjustment, with the day the money moved and a reference. Kept beside the county's published figure, never merged into it. The same entry twice is one entry. Arguments: - `amount` ([`Money!`](/docs/types.md#money), required): The amount in dollars. A payment or a refund is positive; an adjustment may be negative. Never zero. - `effectiveDate` ([`Date!`](/docs/types.md#date), required): The day the money moved. - `installmentId` (`ID!`, required): The installment the money was for, by its id. - `kind` ([`PaymentKind!`](/docs/types.md#paymentkind), required): A payment, a refund, or an adjustment. - `note` (`String`): Anything the next reader should know about the entry. - `reference` (`String`): A check number, a confirmation, a ledger line. Example: ```graphql mutation ($amount: Money!, $effectiveDate: Date!, $installmentId: ID!, $kind: PaymentKind!) { recordPayment( amount: $amount effectiveDate: $effectiveDate installmentId: $installmentId kind: $kind ) { recorded installment { id status amountDue amountOutstanding amountPaid } } } ``` ### rejectBill `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Reject a bill as a wrong reading: NEEDS_REVIEW or DISPUTED becomes REJECTED, on every installment named or on none. Final, and left out of every total and deadline; undoBillReview takes it back within 10 minutes. A later fetch does not reopen it: one that reads other charges is the bill's next revision, waiting for review. Refused with CONFLICT when the bill changed after the version you read (expectedVersion). Arguments: - `expectedVersion` (`Int!`, required): The bill's version as the caller read it (TaxBill.version). If anything about the bill changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `installmentIds` (`[ID!]!`, required): The installments of one bill, from TaxBill.installments. One bill per call. - `reason` (`String!`, required): Why, for the activity trail. Required. Example: ```graphql mutation ($expectedVersion: Int!, $installmentIds: [ID!]!, $reason: String!) { rejectBill( expectedVersion: $expectedVersion installmentIds: $installmentIds reason: $reason ) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### reportBillProblem `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Report a bill that was accepted automatically (TaxBill.acceptedAutomatically) as wrong. It goes back to NEEDS_REVIEW and to retrieve-IQ, who check it against the county and correct it or hand it to you; until then it shows as being checked (TaxBill.retrieveIqCheck) and accepting, flagging and rejecting it are refused. Refused for a bill a person accepted or one not accepted, and with CONFLICT when the bill changed after the version you read (expectedVersion). Arguments: - `expectedVersion` (`Int!`, required): The bill's version as the caller read it (TaxBill.version). If anything about the bill changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `installmentIds` (`[ID!]!`, required): The installments of one bill, from TaxBill.installments. One bill per call. - `note` (`String!`, required): What looks wrong. retrieve-IQ reads it, and it stays in the bill's history. Required. Example: ```graphql mutation ($expectedVersion: Int!, $installmentIds: [ID!]!, $note: String!) { reportBillProblem( expectedVersion: $expectedVersion installmentIds: $installmentIds note: $note ) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### reportRule `mutation`, returns [`RuleReport!`](/docs/types.md#rulereport), needs `PARCEL_READ` Tell the people who maintain the rules that a rule or a filing requirement is wrong. The report keeps what the product showed for that rule and year at filing, and its status shows in ruleReports when they answer. A rule itself changes only through the reviewed dataset. Arguments: - `input` ([`ReportRuleInput!`](/docs/types.md#reportruleinput), required): The rule, the year, and what is wrong with it. Example: ```graphql mutation ($input: ReportRuleInput!) { reportRule(input: $input) { id status assessmentYear createdAt evidenceUrl problem resolution resolvedAt jurisdiction { id name assesses billDelivery bills } reportedBy { id name email } } } ``` ### requestReport `mutation`, returns [`ReportJob!`](/docs/types.md#reportjob), needs `REPORT_READ` Request a report. It is produced in the background with the access this request has: the engagement's scopes, capped by the key's, checked again when it runs. The key needs REPORT_READ and the scopes the report reads with (reportCatalog names them); one without them is refused here. The job carries downloadUrl once DONE. Poll reportJob or reportJobs. Arguments: - `filter` ([`ReportFilter`](/docs/types.md#reportfilter)): Which parcels. The whole portfolio when omitted. - `format` ([`ReportFormat!`](/docs/types.md#reportformat), required): The file format. - `kind` ([`ReportKind!`](/docs/types.md#reportkind), required): Which report, from reportCatalog. Example: ```graphql mutation ($format: ReportFormat!, $kind: ReportKind!) { requestReport(format: $format, kind: $kind) { id name status byteSize downloadUrl error filterDescription finishedAt requestedBy { id name email } } } ``` ### rerunReport `mutation`, returns [`ReportJob!`](/docs/types.md#reportjob), needs `REPORT_READ` Queue a report again as it was asked for: the kind, the format and the filter of the job named, which may have failed or expired. The new job is yours and renders under your context, as requestReport's do; an appeal its filter names that you can no longer read refuses it as NOT_ENTITLED, with nothing queued. Arguments: - `id` (`ID!`, required): The ReportJob to ask for again. Example: ```graphql mutation ($id: ID!) { rerunReport(id: $id) { id name status byteSize downloadUrl error filterDescription finishedAt requestedBy { id name email } } } ``` ### resolveValidation `mutation`, returns [`ResolveValidationPayload!`](/docs/types.md#resolvevalidationpayload), needs `BILL_REVIEW` and `BILL_READ` Accept a discrepancy a check found: the check records who, when and the note (Validation.resolutionNote), its history keeps them for good (Validation.history), and the bill is no longer withheld once no check stands. There is no un-resolve; a wrong resolution is followed by a rejection or a re-fetch, both of which leave a record. The note is required because the next reader asks why. The bill's version moves (TaxBill.version), so a decision made from a read before the resolution is refused with CONFLICT. Arguments: - `id` (`ID!`, required): The check (a Validation) to resolve. - `note` (`String!`, required): Why the discrepancy is acceptable. Required. Example: ```graphql mutation ($id: ID!, $note: String!) { resolveValidation(id: $id, note: $note) { bill { key status annualTotal assessmentYear billNumber } validation { id clearedAt code createdAt expected } } } ``` ### revokeApiKey `mutation`, returns [`ApiKey!`](/docs/types.md#apikey), signed-in people only End one of your firm's keys. It stops working at once for the API and the MCP server, a calendar feed it created stops answering, and a report it requested that has not run yet fails. The record stays, with the time. For people signed in to the app: refused while acting for a client. Arguments: - `id` (`ID!`, required): The key. Example: ```graphql mutation ($id: ID!) { revokeApiKey(id: $id) { id name status createdAt expiresAt lastUsedAt prefix revokedAt } } ``` ### revokeCalendarFeed `mutation`, returns [`CalendarFeed!`](/docs/types.md#calendarfeed), needs `PARCEL_READ` End a calendar feed. Its record stays; the URL answers 404 from now on. Arguments: - `id` (`ID!`, required): The feed. Example: ```graphql mutation ($id: ID!) { revokeCalendarFeed(id: $id) { id createdAt label lastFetchedAt revokedAt createdBy { id name email } } } ``` ### setLegalEntityTaxId `mutation`, returns [`LegalEntityPayload!`](/docs/types.md#legalentitypayload), needs `ADMIN` and `PARCEL_READ` Store a legal entity's tax identification number (an EIN, nine digits however typed), kept encrypted. Only the last four digits are ever returned; the trail records that a number was set, never the number. An administrator's act: ADMIN on the engagement, with PARCEL_WRITE. Arguments: - `legalEntityId` (`ID!`, required): The legal entity, by its id. - `taxId` (`String!`, required): The number as written, with or without its dash: nine digits. Example: ```graphql mutation ($legalEntityId: ID!, $taxId: String!) { setLegalEntityTaxId(legalEntityId: $legalEntityId, taxId: $taxId) { legalEntity { id name taxIdLast4 } } } ``` ### startDocumentUpload `mutation`, returns [`DocumentUploadLink!`](/docs/types.md#documentuploadlink), needs `BILL_REVIEW` Start an upload for a parcel: a county's bill PDF, read when the product reads that county's bills exactly, or a client's own export, kept as evidence. Returns a link for the bytes, good once, for fifteen minutes. Arguments: - `input` ([`StartDocumentUploadInput!`](/docs/types.md#startdocumentuploadinput), required): The parcel, what the document is, its name and its exact size. Example: ```graphql mutation ($input: StartDocumentUploadInput!) { startDocumentUpload(input: $input) { expiresAt maxBytes method uploadPath } } ``` ### undoBillReview `mutation`, returns [`BillReviewPayload!`](/docs/types.md#billreviewpayload), needs `BILL_REVIEW` and `BILL_READ` Take back your own acceptance, flag or rejection of a bill within 10 minutes: each installment returns to the status it had before, and both the decision and its undoing stay in the activity trail. expectedVersion is the version the decision's answer carried; CONFLICT when the bill changed since. Refused with UNDO_REFUSED and a reason (NO_DECISION, ALREADY_UNDONE, NOT_YOURS, EXPIRED, CHANGED) otherwise. Arguments: - `expectedVersion` (`Int!`, required): The bill's version as the decision being taken back left it (BillReviewPayload.bill.version). - `installmentIds` (`[ID!]!`, required): The installments of the bill whose decision to take back. Example: ```graphql mutation ($expectedVersion: Int!, $installmentIds: [ID!]!) { undoBillReview( expectedVersion: $expectedVersion installmentIds: $installmentIds ) { notVisible bill { key status annualTotal assessmentYear billNumber } } } ``` ### updateAppeal `mutation`, returns [`Appeal!`](/docs/types.md#appeal), needs `APPEAL_WRITE` and `PARCEL_READ` Change what an appeal asks for, when its window closes, or its note. While the appeal is open or filed: requestedValue (null clears it), deadlineOn (the person's own date) or deadlineFromRule (the jurisdiction's window again, which is no date where the rule gives none exact). At any status: note (null or empty clears it), which is how a decided or withdrawn appeal is corrected. Only the arguments given change, and a change to what the appeal already holds is refused as nothing to change. The trail records each change, from and to. CONFLICT when the appeal changed after expectedVersion was read. Arguments: - `appealId` (`ID!`, required): The appeal, by its id. - `deadlineFromRule` (`Boolean`): True takes the window's close from the jurisdiction's rule again, which is no date where the rule gives none exact. Not with deadlineOn. - `deadlineOn` ([`Date`](/docs/types.md#date)): The day the appeal's window closes, as you know it. Only while the appeal is open or filed; it cannot be cleared, deadlineFromRule puts the rule's date back. - `expectedVersion` (`Int!`, required): The appeal's version as the caller read it (Appeal.version). If the appeal changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `note` (`String`): The appeal's note; null or empty clears it. At any status. - `requestedValue` ([`Money`](/docs/types.md#money)): The value the appeal asks for, in dollars; null clears it. Only while the appeal is open or filed. Example: ```graphql mutation ($appealId: ID!, $expectedVersion: Int!) { updateAppeal(appealId: $appealId, expectedVersion: $expectedVersion) { id status assessedValue assessmentYear createdAt deadlineOn deadlineReason deadlineSource parcel { id parcelNumber status useCode } openedBy { id name email } } } ``` ### updateAppealStatus `mutation`, returns [`Appeal!`](/docs/types.md#appeal), needs `APPEAL_WRITE` and `PARCEL_READ` FILE an appeal (with filedOn), WITHDRAW it, or REOPEN a withdrawn one; WITHDRAW and REOPEN clear filedOn. A decided appeal is final: only its note can change, through updateAppeal. Refused with CONFLICT when the appeal changed after the version you read (expectedVersion). Arguments: - `action` ([`AppealAction!`](/docs/types.md#appealaction), required): The move to make. - `appealId` (`ID!`, required): The appeal. - `expectedVersion` (`Int!`, required): The appeal's version as the caller read it (Appeal.version). If the appeal changed since, the call is refused as a CONFLICT (reason STALE_VERSION) and nothing is written. - `filedOn` ([`Date`](/docs/types.md#date)): When it was filed. With FILE. - `note` (`String`): Replaces the note on the appeal. Example: ```graphql mutation ($action: AppealAction!, $appealId: ID!, $expectedVersion: Int!) { updateAppealStatus( action: $action appealId: $appealId expectedVersion: $expectedVersion ) { id status assessedValue assessmentYear createdAt deadlineOn deadlineReason deadlineSource parcel { id parcelNumber status useCode } openedBy { id name email } } } ``` ### upsertParcel `mutation`, returns [`UpsertParcelPayload!`](/docs/types.md#upsertparcelpayload), needs `PARCEL_WRITE` and `PARCEL_READ` Add a parcel to the portfolio. Safe to repeat: a parcel already held comes back with created false and nothing changed. Arguments: - `input` ([`ParcelInput!`](/docs/types.md#parcelinput), required): The parcel. Example: ```graphql mutation ($input: ParcelInput!) { upsertParcel(input: $input) { created parcel { id parcelNumber status useCode } } } ``` # Types > Every type a query or mutation reaches: objects, inputs, enums, unions, interfaces and scalars. ## Objects ### ActivityEvent `object` One line of a parcel's activity trail: what happened, when, and who did it. Every change made through the app or the API writes one, and so does every fetch. Fields: - `actor` ([`User`](/docs/types.md#user)): The person who acted. Null when retrieve-IQ acted on its own, as for a nightly fetch. - `at` ([`DateTime!`](/docs/types.md#datetime)): When it happened. - `id` (`ID!`): The id of this record. Not a Node id: node does not accept it. - `payload` ([`JSON`](/docs/types.md#json)): The details as structured data. The shape depends on the event. - `summary` (`String!`): The event in one sentence. ### Address `object` The property's street address, as the county publishes it. Every field may be null; a county's record is not always complete. Fields: - `city` (`String`): The city. - `county` (`String`): The county, where the county publishes it. - `line1` (`String`): The street address. - `line2` (`String`): A suite or unit, where there is one. - `postalCode` (`String`): The ZIP code. - `state` (`String`): The two-letter state code. ### ApiKey `object`, implements `Node`, signed-in people only One of your firm's API keys. Its secret was shown once, when it was created; only its first characters are kept, to tell it apart. Fields: - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When it was created. - `expiresAt` ([`DateTime`](/docs/types.md#datetime)): When it stops working. Null for a key with no last day. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `lastUsedAt` ([`DateTime`](/docs/types.md#datetime)): When it was last used, to the minute. Null until it has been. - `name` (`String!`): What it is for, as named when it was created. - `prefix` (`String!`): riq_ and the next eight characters of the secret, to tell keys apart. - `revokedAt` ([`DateTime`](/docs/types.md#datetime)): When it was revoked. Null while it stands. - `scopes` ([`[Scope!]!`](/docs/types.md#scope)): What the key may do, within what the firm itself may do. - `status` ([`ApiKeyStatus!`](/docs/types.md#apikeystatus)): Whether it works. ### ApiKeyCreated `object` A new key and its secret, which this is the only chance to see. Fields: - `apiKey` ([`ApiKey!`](/docs/types.md#apikey)): The key. - `secret` (`String!`): The secret, shown once and never stored. Put it where your system will read it now. ### Appeal `object`, implements `Node`, needs `PARCEL_READ` An appeal of one assessment year, recorded and tracked: open, filed, decided or withdrawn, and changed in place while it is open or filed (updateAppeal). Its evidence is the APPEAL_EVIDENCE_PACK report, for one appeal or several. Hearings are not tracked. Fields: - `assessedValue` ([`Money`](/docs/types.md#money)): The value as first certified for the year. Null when no assessment is held for it. - `assessmentYear` (`Int!`): The year of the assessed value under appeal. - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When it was recorded. - `deadlineOn` ([`Date`](/docs/types.md#date)): The last day to file. Null where the unit sets it from an event whose date is not on record; deadlineReason says why. - `deadlineReason` (`String`): Why deadlineOn is null, in words. Null when there is a date. - `deadlineSource` (`String`): rule, when the date came from the unit's filing window; user, when a person entered it. - `decidedOn` ([`Date`](/docs/types.md#date)): When it was decided. Null until it is. - `decidedValue` ([`Money`](/docs/types.md#money)): The value the board set. Null until decided. - `filedOn` ([`Date`](/docs/types.md#date)): When it was filed. Null until it is. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `note` (`String`): A note for whoever reads the appeal next. - `openedBy` ([`User`](/docs/types.md#user)): The person who recorded it. - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel under appeal. - `payableYear` (`Int!`): The year the bill on that value falls due. - `requestedValue` ([`Money`](/docs/types.md#money)): The value the appeal asks for. Null when none was recorded. - `ruleDeadlineOn` ([`Date`](/docs/types.md#date)): When the unit's rules say the window closes, whatever date the appeal holds (updateAppeal with deadlineFromRule puts it back); null where the rules give no exact date. - `savings` ([`Money`](/docs/types.md#money)): The tax saved, as entered from the corrected bill. Null means not yet known, never zero. - `status` ([`AppealStatus!`](/docs/types.md#appealstatus)): Where the appeal stands. - `valueReduction` ([`Money`](/docs/types.md#money)): The assessed value minus the decided value; negative when the board raised it. Null until decided, or without an assessment. - `version` (`Int!`): Moves on every change to the appeal. updateAppeal, updateAppealStatus and recordAppealOutcome take the version their caller read as expectedVersion, and are refused with CONFLICT when it has moved. ### AppealRequirement `object` What an appeal filing needs beyond its dates, with the provision that states it and the source it comes from; a requirement nobody sourced is absent, never guessed. Each one is looked up through the unit, its parent and its state, the nearest answering. Fields: - `citation` (`String`): The provision, as the source numbers it. - `code` (`String!`): The requirement's stable key within its unit. - `effectiveFromYear` (`Int!`): The first assessment year it governs. - `effectiveToYear` (`Int`): The last assessment year it governs; null while it still does. - `history` ([`[RequirementVersion!]!`](/docs/types.md#requirementversion)): Earlier versions of it, newest first. Empty for one that never changed. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit that holds the requirement. - `recordedAt` ([`DateTime!`](/docs/types.md#datetime)): When this version was written. - `requirement` (`String!`): The requirement in a sentence or two. - `source` (`String!`): Where it comes from. - `sourceUrl` (`String`): A link to the source itself, where one exists. - `topic` ([`AppealRequirementTopic!`](/docs/types.md#appealrequirementtopic)): What part of the filing it is about. - `verifiedAt` ([`Date`](/docs/types.md#date)): When a person last confirmed it; null means nobody has. - `verifiedBy` (`String`): Who confirmed it. - `version` (`Int!`): How many times it has changed, counting from 1. ### AppealRule `object` The appeal filing window for one assessment year, from the unit's own rules, then its parent's, then the state's. opensOn and closesOn are the rules as recorded (a fixed day, an event plus a number of days, an nth weekday, or the later or the earlier of two); the dates are what they yield for the year; reason says in words why the close has no date. What a filing needs beyond its dates (the board, the form, an agent's authorization) is Jurisdiction.appealRequirements, and the source behind each rule is Jurisdiction.rules. Fields: - `closesOn` (`String`): The closing rule as recorded. Null when none is recorded, or the unit sets the date each year. - `closesOnDate` (`String`): The last day to file, YYYY-MM-DD. Null when the rule does not yield a date; never guessed. - `opensOn` (`String`): The opening rule as recorded. Null when none is recorded, or the unit sets the date each year. - `opensOnDate` (`String`): The first day to file, YYYY-MM-DD. Null when the rule does not yield a date. - `qualifier` (`String`): exact, or no_earlier_than or no_later_than when one side of a later-of or earlier-of rule is an event whose date is not on record: a bound, not the deadline. - `reason` (`String`): Why closesOnDate is null, in plain words. - `resolvedFrom` ([`Jurisdiction`](/docs/types.md#jurisdiction)): The unit whose rule answered: the unit itself, its parent, or the state. - `source` (`String`): Where the closing rule came from: the statute or the unit's own notice. - `verifiedAt` (`String`): When a person last confirmed the closing rule. Null means not yet verified. ### AppealUpside `object` An estimate of what the open appeals could save, never a promise: over open and filed appeals, the reduction requested times the share of it your decided appeals achieved, times each parcel's effective tax rate. An appeal missing one of those inputs is left out of the sum and counted. Fields: - `appealsWithoutRate` (`Int!`): Open appeals left out for want of an assessed value, a requested value or a billed year to take a rate from. - `basisDecidedAppeals` (`Int!`): Decided appeals the achieved share was learned from. - `modeled` ([`Money`](/docs/types.md#money)): The estimate. Null with no decided appeals to learn from, or nothing to sum. - `openAppeals` (`Int!`): Appeals at OPEN or FILED. - `realizedRatio` (`Float`): Achieved reduction over requested reduction, across decided appeals. ### Assessment `object`, implements `Node`, needs `PARCEL_READ` A parcel's assessed value for one year, as the assessing unit certified it. Fields: - `assessmentYear` (`Int!`): The year the value was set, which an appeal contests. - `certifiedOn` ([`Date`](/docs/types.md#date)): When the unit certified the value, where known. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `improvementValue` ([`Money!`](/docs/types.md#money)): The assessed value of the buildings and other improvements. - `landValue` ([`Money!`](/docs/types.md#money)): The assessed value of the land. - `payableYear` (`Int!`): The year the bill on this value falls due: the same year in most states, the year after in some (Cook County, Illinois). - `revision` (`Int!`): Zero today for every assessment: a value read again replaces the figure on the same revision. Higher revisions are reserved for a correction recorded as one. - `totalValue` ([`Money!`](/docs/types.md#money)): Land plus improvements. ### AutomaticAcceptance `object` How a bill was accepted without a person: read exactly from the county, every check passed, not a $0 bill, and close to last year's. Fields: - `at` ([`DateTime!`](/docs/types.md#datetime)): When the nightly fetch accepted it. - `reason` (`String!`): Why, in words for the customer. ### BillConnection `object` A page of bills. Fields: - `edges` ([`[BillConnectionEdge!]!`](/docs/types.md#billconnectionedge)): The page's records, each with the cursor that continues from it. - `pageInfo` ([`PageInfo!`](/docs/types.md#pageinfo)): Whether more follows, and the cursor to continue from. - `totalCount` (`Int!`): Bills matching the filter, across every page. ### BillConnectionEdge `object` One bill on a page. Fields: - `cursor` (`String!`): Pass this as after to continue from this record. - `node` ([`TaxBill!`](/docs/types.md#taxbill)): The record. ### BillEntryPayload `object` What entering a bill did: its outcome, a sentence saying what happened, and the installments of the bill stored. Fields: - `installments` ([`[TaxBillInstallment!]!`](/docs/types.md#taxbillinstallment)): The installments of the bill stored, in order. Empty unless the outcome is STORED. - `message` (`String!`): What happened, in a sentence the person reads. - `outcome` ([`BillEntryOutcome!`](/docs/types.md#billentryoutcome)): Whether a bill was stored, kept as evidence only, or already on file. ### BillingLevelCount `object` How many units of one level send a property tax bill of their own. Fields: - `count` (`Int!`): How many units of that level send a bill. - `level` (`String!`): The kind of unit: county, city, town, township, school_district and so on. ### BillReviewPayload `object` What a review did. bill is the bill as it stands after it, with the version a next call sends back. notVisible lists the installment ids it did not act on: not visible to you, or not at a status the action moves from; the API does not say which. A bill that changed after you read it is not a payload but a CONFLICT error, and nothing is written. If the response also carries an error, the whole request was undone and nothing changed. Fields: - `bill` ([`TaxBill`](/docs/types.md#taxbill)): The bill after the review. Null when none of the installments named was visible. - `notVisible` (`[ID!]!`): The installment ids the review could not act on. Empty when it acted on every one. ### CalendarFeed `object`, implements `Node`, needs `PARCEL_READ` A subscribable calendar (iCal) of the portfolio's dates. Its URL carries a secret and is shown once, when the feed is created; revoking the feed keeps this record and ends the URL. Fields: - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When it was created. - `createdBy` ([`User`](/docs/types.md#user)): The person who created it. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `label` (`String!`): Where it is used, as named when it was created. - `lastFetchedAt` ([`DateTime`](/docs/types.md#datetime)): When a calendar app last read it. Null until one has. - `revokedAt` ([`DateTime`](/docs/types.md#datetime)): When it was revoked. Null while it is in force. ### CalendarFeedCreated `object` A new feed and, this once, the URL that carries its secret. Fields: - `feed` ([`CalendarFeed!`](/docs/types.md#calendarfeed)): The feed. - `url` (`String!`): Subscribe to this in Outlook, Google Calendar or Apple Calendar. It is not shown again. ### CountyIngestionStatus `object` What the nightly fetch did in one county: the newest outcome, when the county last answered (with a bill, or with NOT_FOUND), the current run of failures, and the last day's attempts. Fields: - `attempts24h` (`Int!`): Attempts in the last 24 hours. - `failures24h` (`Int!`): Of those, how many failed. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The county. - `lastAnsweredAt` ([`DateTime`](/docs/types.md#datetime)): When the county last answered, with a bill or with NOT_FOUND. - `lastAttemptAt` ([`DateTime`](/docs/types.md#datetime)): When a fetch was last attempted there. - `lastOutcome` ([`IngestOutcome`](/docs/types.md#ingestoutcome)): How the newest attempt ended. - `lastSuccessAt` ([`DateTime`](/docs/types.md#datetime)): When a bill was last fetched there. - `parcels` (`Int!`): Parcels of the portfolio in the county. - `streak` (`Int!`): How many attempts in a row have failed, counting back from the newest. Zero when the county answered last. ### CountyOutstanding `object` One unit that bills a parcel in the portfolio (a county, a township, a school district), and what is owed to it. The rows are billing units of any level, under a name kept for compatibility. Fields: - `amountOutstanding` ([`OutstandingTotal!`](/docs/types.md#outstandingtotal)): What is owed to this unit, and how complete that figure is. Needs BILL_READ. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit that bills, which need not be the unit that assesses the parcel. - `parcelCount` (`Int!`): Distinct parcels this unit bills. A parcel billed by three units counts once in each. ### Coverage `object` Where bills can be fetched, by state and by county, from the registry of taxing units and their sites. Fields: - `counties` ([`[CoverageUnit!]!`](/docs/types.md#coverageunit)): Every unit with a county FIPS code, for a county map: the county-level units, Alaska's census areas and the regions that stand for counties where the county does not govern (Connecticut, Massachusetts, Rhode Island). - `countyTotals` ([`CoverageCounts!`](/docs/types.md#coveragecounts)): The county-level units only, which is the headline figure: counties, parishes, independent cities and Alaska's boroughs. - `states` ([`[StateCoverage!]!`](/docs/types.md#statecoverage)): By state, in code order. - `totals` ([`CoverageCounts!`](/docs/types.md#coveragecounts)): Every registered unit in the country. - `units` ([`[CoverageUnit!]!`](/docs/types.md#coverageunit)): The named units, of any level; a code the registry does not hold is left out. At most 500 at a time. - `unitCodes` (`[String!]!`, required): Unit codes, as Jurisdiction.unitCode has them. ### CoverageCounts `object` Units counted by coverage status. The statuses add up to units. Fields: - `assessmentOnly` (`Int!`): At ASSESSMENT_ONLY. - `closed` (`Int!`): At CLOSED. - `covered` (`Int!`): At COVERED. - `noPortal` (`Int!`): At NO_PORTAL. - `notSurveyed` (`Int!`): At NOT_SURVEYED. - `other` (`Int!`): At OTHER. - `portalFound` (`Int!`): At PORTAL_FOUND. - `readerReady` (`Int!`): At READER_READY. - `retired` (`Int!`): At RETIRED. - `units` (`Int!`): All of them. ### CoverageUnit `object` One taxing unit and whether its bills can be fetched. Fields: - `assesses` (`Boolean!`): Whether the unit sets assessed values. - `bills` (`Boolean!`): Whether the unit sends a property tax bill of its own. - `countyLevel` (`Boolean!`): A county, parish, independent city or one of Alaska's boroughs: the units the headline figure counts. - `fips` (`String`): The five-digit county FIPS code, for a county or its equivalent. - `level` (`String!`): The kind of unit: county, city, town, township, school_district and so on. - `name` (`String!`): As the unit names itself. - `portals` ([`[Portal!]!`](/docs/types.md#portal)): Every site recorded for the unit, the one that decided the status first. - `state` (`String!`): The two-letter state code. - `status` ([`CoverageStatus!`](/docs/types.md#coveragestatus)): Whether the unit's bills can be fetched. - `unitCode` (`String!`): The code of the unit, as Jurisdiction.unitCode has it. - `vendor` (`String`): The software behind the site that decided the status. ### Deadline `object`, implements `Node` A payment or appeal date, worked out from a bill or from the unit's rules and saved, so that a change to it is traced and a person can acknowledge it. The saved dates are brought up to date when someone who may read bills reads them after the portfolio, a bill or a rule changed; a date that moved keeps a trace of the one it replaced, and starts unacknowledged. Fields: - `acknowledgedAt` ([`DateTime`](/docs/types.md#datetime)): When a person acknowledged this date; null until then, and again once the date moves. - `acknowledgedBy` ([`User`](/docs/types.md#user)): The person who acknowledged it. - `assessmentYear` (`Int!`): The assessment year the date belongs to. - `exposure` ([`Money`](/docs/types.md#money)): What is at stake: the balance still owed, for a payment date. Null when the balance is unknown, and for an appeal date; never read a null as zero. The dates are read with PARCEL_READ; the balance is bill data. Needs BILL_READ. - `generatedAt` ([`DateTime!`](/docs/types.md#datetime)): When this date was worked out. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): For a payment date: the unit the bill is owed to. For an appeal date: the unit that assesses the parcel and hears the appeal, or, for the unit's own window, the unit itself. - `kind` ([`DeadlineKind!`](/docs/types.md#deadlinekind)): What the date is. - `on` ([`Date`](/docs/types.md#date)): The date. Null when the rule could not be evaluated; unevaluableReason says why. - `paidPerRecords` (`Boolean!`): True for a payment date whose installment the county publishes no payment figure for and the customer's own records show paid in full: the date stays, marked, since the county has not confirmed it. Bill data, as exposure is. Needs BILL_READ. - `parcel` ([`Parcel`](/docs/types.md#parcel)): The parcel the date belongs to. Null for a date that belongs to the unit rather than to a parcel: the unit's own appeal window, which stands whichever parcels it assesses. - `qualifier` (`String`): For an appeal date: exact, or no_earlier_than or no_later_than when one side of a later-of or earlier-of rule is an event whose date is not on record. A bound, not the deadline. - `resolvedFrom` ([`Jurisdiction`](/docs/types.md#jurisdiction)): For an appeal date: the unit whose rule answered (the unit, its parent, or the state). - `source` (`String!`): BILL for a payment date read off a bill; JURISDICTION_RULE for an appeal window from the assessing unit's rules. - `supersedes` ([`DeadlineChange`](/docs/types.md#deadlinechange)): The date or reason this one replaced, when it moved; null for a date that never changed. - `taxAccount` ([`TaxAccount`](/docs/types.md#taxaccount)): For a payment date: the account the bill belongs to. Null for an appeal date, which belongs to the parcel however many units bill it. - `unevaluableReason` (`String`): Why there is no date, in words. ### DeadlineChange `object` What a saved date replaced when it moved: the date or the reason it had before, which explains a change a subscribed calendar shows. Fields: - `on` ([`Date`](/docs/types.md#date)): The date it had before; null when it had none. - `unevaluableReason` (`String`): Why it had no date before, when it had none. ### DeadlineGeneration `object` When the saved dates were last worked out from the bills and rules, and whether a change since is waiting on it. Fields: - `generatedAt` ([`DateTime`](/docs/types.md#datetime)): When the dates were last generated. Null before the first time: the portfolio has no dates yet. - `stale` (`Boolean!`): A change saved since generatedAt (a bill, a correction, a payment, a parcel, a night's fetch, or a rule or notice date the appeal windows are worked out from) is not in the dates yet. They are regenerated when someone who may read bills next opens them; a reader who may not reads them as they stand. ### Document `object`, implements `Node`, needs `BILL_READ` A file held as evidence: the page a county served when the bill was fetched. The bytes are fetched from contentPath, not through GraphQL. Fields: - `byteSize` (`Int`): Its size in bytes, where known. - `contentPath` (`String!`): GET this path, with the same Authorization and X-Engagement-ID headers, to read the bytes. HTML from a county is served in a sandbox. - `extractions` ([`[Extraction!]!`](/docs/types.md#extraction)): Every reading of the document. - `fileRemovedAt` ([`DateTime`](/docs/types.md#datetime)): When the file was removed, seven years after it arrived, whether a person uploaded it or it was read from a county site. Null while it is kept. What was read from it stays, and so does the record that it was removed. - `filename` (`String!`): The name it was fetched or uploaded under. - `hasBill` (`Boolean!`): Whether a bill was read from this document, by the product or entered by hand. A tax bill without one is evidence a person may enter by hand (enterBill). - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `kind` ([`DocumentKind!`](/docs/types.md#documentkind)): What the document is. - `mediaType` (`String`): What the file is, as recognised from its bytes when it arrived; null for a document kept from before that was recorded. - `pageCount` (`Int`): Its page count, for a PDF. - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel the document belongs to. - `receivedAt` ([`DateTime!`](/docs/types.md#datetime)): When it arrived. - `receivedVia` (`String!`): How it arrived: portal for a page read from the unit's site, upload for a file a person added. email and sftp are reserved. - `sourceUrl` (`String`): The county page it was fetched from. Null for an upload. - `uploadedBy` ([`User`](/docs/types.md#user)): The person who uploaded it; null for a document read from the unit's site. ### DocumentLink `object` A link that opens one document's bytes without a header, until expiresAt. Re-authorized when opened: an engagement that ended in between opens nothing. Fields: - `expiresAt` ([`DateTime!`](/docs/types.md#datetime)): When the link stops opening: five minutes after it was made. - `path` (`String!`): Where the document opens, on this API's host. It holds the link's secret. ### DocumentUploadLink `object` Where to send the bytes: PUT them to uploadPath with the same bearer token, once, before expiresAt. Shown once. Fields: - `expiresAt` ([`DateTime!`](/docs/types.md#datetime)): When the link stops taking the bytes: fifteen minutes after it was made. - `maxBytes` (`Int!`): The largest file this environment takes. - `method` (`String!`): The HTTP method to send them with: PUT. - `uploadPath` (`String!`): Where to send the bytes, on this API's host. It holds the link's secret, so it is shown once. ### Engagement `object`, implements `Node` A firm's permission to work on a client's portfolio: which scopes, from when, and until when. Name one on a request with the X-Engagement-ID header. Fields: - `agent` ([`Tenant!`](/docs/types.md#tenant)): The firm that works on it. - `approvalRecorded` (`Boolean!`): Whether authorisedOn, authorisationRef and grantedBy are all on record. False means the engagement was approved before approvals were recorded. - `authorisationRef` (`String`): Where the written approval is kept: a reference, never the document. - `authorisedOn` ([`Date`](/docs/types.md#date)): The day the client gave its written approval; null on an engagement approved before approvals were recorded. - `client` ([`Tenant!`](/docs/types.md#tenant)): The client whose portfolio it is. - `effectiveFrom` ([`Date!`](/docs/types.md#date)): The first day the engagement is in force. - `effectiveTo` ([`Date`](/docs/types.md#date)): The last day the engagement is in force. Null for one with no end date. - `engagementId` (`ID!`): The value to send in the X-Engagement-ID header. Not the same as id. - `grantedBy` (`String`): Who at the client gave the approval, as written on it. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `live` (`Boolean!`): Whether the engagement is in force today: not revoked, begun and not yet ended. One that has lapsed or been revoked is still listed, so the client is not mistaken for a deleted one, but a request under it is refused with FORBIDDEN. - `revokedAt` ([`DateTime`](/docs/types.md#datetime)): When it was revoked; null while it stands. A revoked engagement is not live whatever its dates say. - `revokedReason` (`String`): Why it was revoked, as recorded when it was. - `scopes` ([`[Scope!]!`](/docs/types.md#scope)): What the firm may do for this client. A key may do what both its own scopes and the engagement's allow. ### ExtractedField `object` One figure a reading took: which figure it is, the text as printed, and where it was printed when that was recorded. Fields: - `bbox` (`[Float!]`): Where on that page: [left, top, right, bottom] as fractions of the page's width and height, from its top-left corner. - `confidence` (`Float`): Null when the reading is exact: a county's own text read by its reader, or a person's entry. A number in [0, 1] only from a model. - `elementId` (`String`): The element of the county's HTML page it was read from. - `key` (`String!`): Which figure it is, as a path: "totalBilled", "installments.amountDue", "lineItems.amount". - `ordinal` (`Int!`): Which one, for a figure that repeats: an installment's number, a charge's place from 1. - `page` (`Int`): The page it was printed on, from 1, for a PDF. - `value` (`String!`): The figure as printed, or as the person entered it. ### Extraction `object`, implements `Node`, needs `BILL_READ` One reading of a document: who or what read it and when, whether it could be believed and why not, and the figures it took with where each was printed. A document keeps all its readings, oldest first; a correction is the next one. Fields: - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When the reading was made. - `createdBy` ([`User`](/docs/types.md#user)): The person, for a reading a person made; null for one the product made. - `engine` (`String`): A short code for the program that read the document; null for a reading a person made. - `error` (`String`): Why the reading could not be believed, when it could not. - `fields` ([`[ExtractedField!]!`](/docs/types.md#extractedfield)): The figures it took, each with where it was printed. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `pages` ([`[PageSize!]`](/docs/types.md#pagesize)): The size of each page it read, for a PDF, so each figure can be shown where it was printed. - `reviewedAt` ([`DateTime`](/docs/types.md#datetime)): When a person confirmed the reading. - `reviewedBy` ([`User`](/docs/types.md#user)): The person who confirmed it. - `state` ([`ExtractionState!`](/docs/types.md#extractionstate)): How far the reading has got. - `version` (`Int!`): Its place among the document's readings, oldest first. ### FeedRun `object` One night of the feed for one client: its fetch, the files produced and delivered, and how it went. Read under the client's engagement. Fields: - `deliveredTo` (`String`): Where the files went: an SFTP host, an S3 bucket or a folder. - `feedName` (`String!`): The feed, as named in its setup. - `finishedAt` ([`DateTime`](/docs/types.md#datetime)): When it finished. Null while it runs. - `id` (`ID!`): The id of this record. Not a Node id: node does not accept it. - `message` (`String`): What happened, in words, when something did. - `outcome` ([`FeedOutcome!`](/docs/types.md#feedoutcome)): How it ended. - `startedAt` ([`DateTime!`](/docs/types.md#datetime)): When the night started. ### InboxSummary `object` The inbox in numbers: what arrived this week, what could not be read, and what waits, by status. Fields: - `beingChecked` (`Int!`): Bills retrieve-IQ is checking before you act on them (TaxBill.retrieveIqCheck). They are not in the queue. - `disputed` (`Int!`): Waiting bills with an installment flagged for the client, which makes the bill DISPUTED. - `failedExtractionsThisWeek` (`Int!`): Of this week's pages, how many could not be read: nothing was taken from them, and each needs a look. - `needsReview` (`Int!`): Waiting bills at NEEDS_REVIEW. - `receivedThisWeek` (`Int!`): Bill pages and files received in the last seven days. - `withheld` (`Int!`): Waiting bills an ERROR check stands against. ### Jurisdiction `object`, implements `Node` A taxing unit: a county, a city, a township, a school district, a special district, or a state. A unit may assess property, bill it, or both. The same registry for every caller. Fields: - `appealRequirements` ([`[AppealRequirement!]!`](/docs/types.md#appealrequirement)): What an appeal filed here for that assessment year needs beyond its dates: the form, the agent's authorization, what the application says, where it goes. Empty when nothing is recorded. - `assessmentYear` (`Int!`, required): The assessment year the appeal is about. - `appealRule` ([`AppealRule!`](/docs/types.md#appealrule)): The appeal filing window for an assessment year, from the unit's own rules, then its parent's, then the state's. - `assessmentYear` (`Int!`, required): The assessment year the window belongs to. - `assesses` (`Boolean!`): Whether this unit sets assessed values and hears appeals. - `billDelivery` ([`BillDelivery!`](/docs/types.md#billdelivery)): How the unit makes its bill available. - `bills` (`Boolean!`): Whether this unit sends a property tax bill of its own. - `fipsCode` (`String`): The five-digit county FIPS code, for a county or its equivalent. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `installmentsPerYear` (`Int!`): How many installments the unit splits its annual bill into. - `kind` (`String!`): The office that collects the tax, as the unit names it: "Treasurer-tax collector". - `level` (`String!`): What the unit is: state, county, independent_city, city, town, township, village, borough, parish, school_district, special_district or region. A state holds statewide defaults and neither assesses nor bills. - `name` (`String!`): As the unit names itself: "Los Angeles County". - `parcelCount` (`Int!`): How many parcels of the portfolio this unit assesses or bills, which is what ParcelFilter.jurisdictionIds returns for it. Not the number of parcels in the unit. - `rules` ([`[JurisdictionRule!]!`](/docs/types.md#jurisdictionrule)): Every kind of dated rule for an assessment year, in the order a filing season runs, each with the evidence behind it. A kind nobody recorded is listed as NOT_RECORDED, never left out. - `assessmentYear` (`Int!`, required): The assessment year to work the rules out for. - `state` (`String!`): The two-letter state code. - `unitCode` (`String!`): A stable code for the unit: US-CA-FIPS-06007 for a county with a Census code, US-CA-STATE for a state, a code of the state's own scheme for a unit below the county. ### JurisdictionRule `object` One kind of rule for one assessment year, worked out exactly as the deadlines are: from the unit's own rules, then its parent's, then the state's, the covering rule with the latest first year winning within a unit, the weekend rule applied. date is never invented: status says why there is none, and reason says it in words. row is the stored rule that answered, with its source; rows is every rule of this kind the unit, its parent and its state hold, so the answer is seen beside the rules it took over from. Fields: - `assessmentYear` (`Int!`): The assessment year it was worked out for. - `date` (`String`): YYYY-MM-DD, after the weekend rule; null unless status is DATED or BOUND. - `kind` ([`RuleKind!`](/docs/types.md#rulekind)): Which dated rule it is. - `qualifier` (`String`): exact, or no_earlier_than / no_later_than for a BOUND date. - `reason` (`String`): Why there is no date, in plain words. - `resolvedFrom` ([`Jurisdiction`](/docs/types.md#jurisdiction)): The unit whose row answered. - `row` ([`RuleRow`](/docs/types.md#rulerow)): The stored rule that answered; null when none is recorded. - `rows` ([`[RuleRow!]!`](/docs/types.md#rulerow)): Every stored rule of this kind the unit, its parent and its state hold, the one that answered among them. - `status` ([`RuleStatus!`](/docs/types.md#rulestatus)): Whether there is a date, and if not, why not. - `unadjustedDate` (`String`): The date the rule itself names, when the weekend rule moved it (a Saturday, Sunday or federal holiday); null when nothing moved. ### LegalEntity `object`, implements `Node`, needs `PARCEL_READ` An owner of record: the company or other entity the parcels are held under. Fields: - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `name` (`String!`): The name on the roll. - `taxIdLast4` (`String`): The last four digits of the tax identification number on file, or null when none is. The whole number is never returned. ### LegalEntityHolding `object` One owner of record in the portfolio and what it holds: the breakdown by owner beside the one by billing unit. Its parcels, their assessed value counted the overview's way (the newest assessment of each active parcel), and what is owed on their bills. Fields: - `amountOutstanding` ([`OutstandingTotal!`](/docs/types.md#outstandingtotal)): What is owed on the bills of the entity's parcels, counted as amountOutstanding counts: unknown and withheld installments set aside and said. Needs BILL_READ. - `assessedValue` ([`Money!`](/docs/types.md#money)): The newest assessment of each of the entity's active parcels, summed: the same rule as PortfolioSummary.totalAssessedValue, so the entities add up to it. "0.00" when none is assessed. - `assessedValueAsOf` (`Int`): The newest assessment year behind that figure. Null when none of its parcels is assessed. - `legalEntity` ([`LegalEntity!`](/docs/types.md#legalentity)): The owner of record. - `parcelCount` (`Int!`): Every parcel filed to the entity, whatever its status: what the parcel list filtered by the entity shows. ### LegalEntityPayload `object` The owner of record after the change. Fields: - `legalEntity` ([`LegalEntity!`](/docs/types.md#legalentity)): As it stands now, with the last four digits of its number. ### OutstandingTotal `object` A balance and how complete it is. A single number would claim more than is known: a county that publishes no payment figures adds nothing to the sum, and leaving that out silently would understate what is owed. Fields: - `installmentCount` (`Int!`): How many installments the figure covers. Zero means no bills are held, which is not the same as owing nothing. - `installmentsPaidPerRecords` (`Int!`): Of the installments with no published payment, how many the customer's own records show paid in full. Said beside the figure, never added into it: the county has not confirmed them. - `installmentsWithUnknownPayment` (`Int!`): Installments left out because the county publishes no payment figure for them. - `known` ([`Money!`](/docs/types.md#money)): The sum over the installments whose payment figure the county reports. - `withheldCount` (`Int!`): Installments left out because a check stands against their bill: pending review, neither settled nor unknown. ### PageInfo `object` Where a page sits in its list: whether more follows, and the cursor to continue from. Fields: - `endCursor` (`String`): The last record's cursor: pass it as after for the next page. - `hasNextPage` (`Boolean!`): Whether another page follows this one. - `hasPreviousPage` (`Boolean!`): Whether a page precedes this one. - `startCursor` (`String`): The first record's cursor. ### PageSize `object` The size of a page a reading read, in points (a point is 1/72 of an inch). Fields: - `height` (`Float!`): Its height in points. - `width` (`Float!`): Its width in points. ### Parcel `object`, implements `Node`, needs `PARCEL_READ` A property in the portfolio: its number and address, the unit that assesses it, the units that bill it, and its assessments, bills, dates and appeals. Fields: - `activity` ([`[ActivityEvent!]!`](/docs/types.md#activityevent)): The parcel's activity trail, newest first. - `first` (`Int`, default 20): How many events: 20 when omitted, at most 50. - `amountOutstanding` ([`OutstandingTotal!`](/docs/types.md#outstandingtotal)): What is still owed on this parcel, and how complete that figure is. Needs BILL_READ. - `appeals` ([`[Appeal!]!`](/docs/types.md#appeal)): Every appeal recorded on the parcel, newest year first. - `assessments` ([`[Assessment!]!`](/docs/types.md#assessment)): The assessments on record, newest year first. - `last` (`Int`, default 6): How many years: 6 when omitted, at most 12. - `bills` ([`[TaxBill!]!`](/docs/types.md#taxbill)): The parcel's bills, newest year first. Needs BILL_READ. - `last` (`Int`, default 6): How many bills: 6 when omitted, at most 24. - `currentAssessment` ([`Assessment`](/docs/types.md#assessment)): The newest assessment on record. Null until one is held. - `deadlines` ([`[Deadline!]!`](/docs/types.md#deadline)): The parcel's payment and appeal dates: one per installment, and the appeal window of the newest year that has a bill. A parcel with no bill yet has no appeal dates. - `documents` ([`[Document!]!`](/docs/types.md#document)): Every document held for this parcel, newest first. Needs BILL_READ. - `kind` ([`DocumentKind`](/docs/types.md#documentkind)): Only documents of this kind. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit that assesses the parcel and hears its appeals. The units that bill it are on taxAccounts. - `legalEntity` ([`LegalEntity!`](/docs/types.md#legalentity)): The owner of record the parcel is held under. - `nextPayment` ([`Deadline`](/docs/types.md#deadline)): The soonest payment date that costs money if ignored: a penalty date already passed with a balance known to be owed, otherwise the earliest penalty or due date from today on. A passed date whose payment the county does not publish is not returned. Null when nothing is owed or coming. - `parcelNumber` (`String!`): As the county writes it: the APN in California. - `situsAddress` ([`Address!`](/docs/types.md#address)): The property's street address. - `status` ([`ParcelStatus!`](/docs/types.md#parcelstatus)): Where the parcel stands in the portfolio. - `taxAccounts` ([`[TaxAccount!]!`](/docs/types.md#taxaccount)): The units that bill this property and the numbers they know it by: active first, then oldest first. Empty for a parcel whose billing units are not yet known. - `useCode` (`String`): The county's use code for the property, where it publishes one. ### ParcelCandidate `object` A parcel offered for a number or an address that matched none exactly: the same number in another county or held twice, the same digits without the leading zeros a spreadsheet drops, a check digit or suffix, an address that agrees. Taken only by a person, never by itself. Fields: - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel offered. - `reasons` (`[String!]!`): Why it was offered, in words. - `score` (`Float!`): In [0, 1], to order the candidates; it decides nothing. ### ParcelConnection `object` A page of parcels. Fields: - `edges` ([`[ParcelConnectionEdge!]!`](/docs/types.md#parcelconnectionedge)): The page's records, each with the cursor that continues from it. - `pageInfo` ([`PageInfo!`](/docs/types.md#pageinfo)): Whether more follows, and the cursor to continue from. - `totalCount` (`Int!`): Parcels matching the filter, across every page. ### ParcelConnectionEdge `object` One parcel on a page. Fields: - `cursor` (`String!`): Pass this as after to continue from this record. - `node` ([`Parcel!`](/docs/types.md#parcel)): The record. ### ParcelImportPayload `object` What the import did. Fields: - `created` (`Int!`): Parcels added. - `dryRun` (`Boolean!`): True when nothing was written. - `existing` (`Int!`): Rows whose parcel was already held; nothing changed for them. - `legalEntity` ([`LegalEntity`](/docs/types.md#legalentity)): The owner of record the parcels were held under. Null on a dry run. - `rejected` ([`[ParcelImportRejection!]!`](/docs/types.md#parcelimportrejection)): Rows that were not imported, with the reason for each. ### ParcelImportRejection `object` A row that was not imported, and why. Fields: - `index` (`Int!`): Which row: zero-based, into the rows given. - `reason` (`String!`): Why it was rejected, in words. ### PaymentImportPayload `object` What a list of payments did: how many rows were recorded, how many were already on record, and which were refused. Fields: - `alreadyRecorded` (`Int!`): Rows that named an observation already on record; nothing was written for them. - `dryRun` (`Boolean!`): True when nothing was written. - `recorded` (`Int!`): Rows recorded; on a dry run, the rows that would be. - `rejected` ([`[PaymentImportRejection!]!`](/docs/types.md#paymentimportrejection)): Rows that could not be recorded, by index in the input, with the reason. ### PaymentImportRejection `object` A row that could not be recorded, and why. Fields: - `candidates` ([`[ParcelCandidate!]!`](/docs/types.md#parcelcandidate)): When the row's number matched no parcel exactly, or more than one: the parcels it may mean, strongest first, for a person to choose by sending the row again with parcelId. - `index` (`Int!`): Its place in the rows sent, from 0. - `reason` (`String!`): Why it was refused, in words. ### PaymentObservation `object` One entry in the customer's own payment records for an installment: kept beside the county's published figure, never merged into it. Append-only; a wrong entry is reversed by an adjustment. Fields: - `amount` ([`Money!`](/docs/types.md#money)): Positive for a payment or a refund; signed for an adjustment. - `effectiveDate` ([`Date!`](/docs/types.md#date)): The day the money moved. - `id` (`ID!`): The entry, for telling one from another. Not a Node id. - `kind` ([`PaymentKind!`](/docs/types.md#paymentkind)): A payment, a refund or an adjustment. - `note` (`String`): A note recorded with it. - `recordedAt` ([`DateTime!`](/docs/types.md#datetime)): When it was recorded. - `recordedBy` ([`User`](/docs/types.md#user)): The person who recorded it, or who sent the list it came in with. - `reference` (`String`): A check number, a confirmation, a ledger line. - `source` ([`PaymentSource!`](/docs/types.md#paymentsource)): Whether a person recorded it or a list brought it in. ### Portal `object` One of a unit's sites for bills, or the recorded reason there is none. Fields: - `discoveredOn` ([`Date`](/docs/types.md#date)): When the site was first recorded. - `host` (`String`): The site's host name. - `ready` (`Boolean!`): Supported and waiting only for a final live check. - `reason` ([`UnreachableReason`](/docs/types.md#unreachablereason)): Why it cannot be fetched from, when it cannot. - `status` ([`PortalStatus!`](/docs/types.md#portalstatus)): Its standing. - `url` (`String`): Where bills are looked up. Null when there is no site. - `vendor` (`String`): The software the site runs, by name. - `verifiedOn` ([`Date`](/docs/types.md#date)): When a bill was last fetched from it in a live check. ### PortfolioSummary `object` The portfolio in numbers: how many parcels, how many units bill them, what they are assessed at, and what the open appeals might save. Fields: - `appealUpside` ([`AppealUpside!`](/docs/types.md#appealupside)): An estimate of what the open appeals could save. - `assessedValueAsOf` (`Int`): The newest assessment year behind that figure. Null when nothing is assessed. - `byState` ([`[StateRollup!]!`](/docs/types.md#staterollup)): The same, by state. - `jurisdictionCount` (`Int!`): Distinct units that bill a parcel in the portfolio: the number of rows countiesInPortfolio returns. A Pennsylvania parcel counts three. - `parcelCount` (`Int!`): Parcels in the portfolio. - `totalAssessedValue` ([`Money!`](/docs/types.md#money)): The total of the newest assessed values. ### RecordPaymentPayload `object` The installment the payment was recorded against, as it stands after it. Fields: - `installment` ([`TaxBillInstallment!`](/docs/types.md#taxbillinstallment)): The installment, with its payment records. - `recorded` (`Boolean!`): False when the same observation was already on record. ### ReportCatalogEntry `object` One report that can be produced, and the formats it comes in. Fields: - `category` ([`ReportCategory!`](/docs/types.md#reportcategory)): Which group it belongs to. - `columns` (`[String!]!`): The column headers, in order. - `description` (`String!`): What it contains. - `formats` ([`[ReportFormat!]!`](/docs/types.md#reportformat)): The formats it can be produced in; requestReport refuses any other. - `kind` ([`ReportKind!`](/docs/types.md#reportkind)): The value to request it by. - `name` (`String!`): Its name, as the app shows it. - `scopes` ([`[Scope!]!`](/docs/types.md#scope)): The scopes the report reads with, needed beside REPORT_READ to request it: a key or an engagement without one of them is refused, and a report already queued fails if its access loses one before it runs. ### ReportJob `object`, implements `Node`, needs `REPORT_READ` A report that was requested: queued, running, done (with a download), failed (with the reason in words), or expired (the file has been removed; request it again). Fields: - `byteSize` (`Int`): The size of the file in bytes, once done. - `downloadUrl` (`String`): GET this path, with the same Authorization and X-Engagement-ID headers, to save the file. Only while DONE; null otherwise. - `error` (`String`): Why it failed, in a sentence: the access it was requested under ended or does not cover the report, or it could not be produced and should be requested again. Quote the job id when you ask retrieve-IQ about it. - `filterDescription` (`String!`): Which parcels the report covers, in words: a county, an owner or an appeal by its name where you may read it. - `finishedAt` ([`DateTime`](/docs/types.md#datetime)): When it finished, done or failed. Null before that. - `format` ([`ReportFormat!`](/docs/types.md#reportformat)): The file format asked for. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `kind` ([`ReportKind!`](/docs/types.md#reportkind)): Which report. - `name` (`String!`): The report's name. - `requestedAt` ([`DateTime!`](/docs/types.md#datetime)): When it was requested. - `requestedBy` ([`User`](/docs/types.md#user)): Who requested it. - `rowCount` (`Int`): How many rows the report holds, once done. - `status` ([`ReportJobStatus!`](/docs/types.md#reportjobstatus)): Where the report is. ### RequirementVersion `object` An earlier version of a filing requirement, as it stood before a change replaced it. Fields: - `citation` (`String`): The provision it cited then. - `recordedAt` ([`DateTime!`](/docs/types.md#datetime)): When this version was written. - `requirement` (`String!`): The requirement as it read then. - `source` (`String!`): Where it came from then. - `sourceUrl` (`String`): A link to that source, where one existed. - `supersededAt` ([`DateTime!`](/docs/types.md#datetime)): When the next version replaced it. - `verifiedAt` ([`Date`](/docs/types.md#date)): When a person had last confirmed it; null meant nobody had. - `verifiedBy` (`String`): Who had confirmed it. - `version` (`Int!`): Which version it was, counting from 1. ### ResolveValidationPayload `object` The resolved check, and the bill after it. Fields: - `bill` ([`TaxBill`](/docs/types.md#taxbill)): The bill after the resolution, no longer withheld if this was the last check standing. - `validation` ([`Validation!`](/docs/types.md#validation)): The check, now resolved. ### RetrieveIqCheck `object` retrieve-IQ is checking this bill against the county before anyone acts on it. Accepting, flagging and rejecting it are refused until the check is done. Fields: - `note` (`String`): The words of whoever reported it, or retrieve-IQ's. - `reason` ([`RetrieveIqCheckReason!`](/docs/types.md#retrieveiqcheckreason)): Why retrieve-IQ is checking it. - `since` ([`DateTime!`](/docs/types.md#datetime)): When retrieve-IQ began checking it. ### RuleReport `object`, implements `Node`, needs `PARCEL_READ` A person's report that a rule or a filing requirement is wrong, filed from the rules screen. shown is what the product said when it was filed, as the server read it then. Fields: - `assessmentYear` (`Int!`): The assessment year it is about. - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When it was filed. - `evidenceUrl` (`String`): Where they saw the right value, if they said. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit whose rule the report is about. - `problem` (`String!`): What the person said is wrong. - `reportedBy` ([`User`](/docs/types.md#user)): The person who filed it. - `resolution` (`String`): What the people who maintain the rules found. - `resolvedAt` ([`DateTime`](/docs/types.md#datetime)): When it was answered; null while it is open. - `ruleVersion` (`Int`): The version of the rule row the report was filed against; null when no row was recorded. - `shown` ([`JSON!`](/docs/types.md#json)): The rule or requirement as the product showed it at filing: expression, date, status, source, version. - `status` ([`RuleReportStatus!`](/docs/types.md#rulereportstatus)): Where it stands. - `subject` ([`RuleReportSubject!`](/docs/types.md#rulereportsubject)): What it is about. - `suggested` (`String`): What they said it should be, if they said. ### RuleRow `object` One stored rule: a unit, a kind and the assessment years it governs (never payable years: an appeal contests an assessment), with where it came from and who confirmed it. version counts its changes; history holds every earlier version. Fields: - `answers` (`Boolean!`): Whether this is the row that answers for the year asked about. - `effectiveFromYear` (`Int!`): The first assessment year the row governs. - `effectiveToYear` (`Int`): The last assessment year it governs; null while it still does. - `expression` (`String`): The rule as written (07-02, 11-30+1y, assessment_notice + 30d, 4th tuesday of may, later_of(a, b)). Null means confirmed to be set locally each year. - `history` ([`[RuleVersion!]!`](/docs/types.md#ruleversion)): Earlier versions of this row, newest first. Empty for a row that never changed. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit that holds the row: the unit itself, its parent, or the state. - `kind` ([`RuleKind!`](/docs/types.md#rulekind)): Which dated rule it is. - `note` (`String`): A note on the rule from the people who maintain the rules. - `recordedAt` ([`DateTime!`](/docs/types.md#datetime)): When this version was written. - `source` (`String!`): Where the rule came from, as the dataset names it. - `sourceUrl` (`String`): A link to the source itself, where one exists. - `verifiedAt` ([`Date`](/docs/types.md#date)): When a person last confirmed the row against its source; null means nobody has. - `verifiedBy` (`String`): Who confirmed it. - `version` (`Int!`): How many times the row has changed, counting from 1. - `weekendRule` ([`WeekendRule!`](/docs/types.md#weekendrule)): What happens to a date on a weekend or a holiday. ### RuleVersion `object` An earlier version of a stored rule, as it stood before a change replaced it. The change may be the rule, its source, or a person confirming it. Fields: - `effectiveToYear` (`Int`): The last assessment year it governed then; null meant it still did. - `expression` (`String`): The rule as it was written then; null meant set locally each year. - `note` (`String`): Its note then. - `recordedAt` ([`DateTime!`](/docs/types.md#datetime)): When this version was written. - `source` (`String!`): Where the rule came from then. - `sourceUrl` (`String`): A link to that source, where one existed. - `supersededAt` ([`DateTime!`](/docs/types.md#datetime)): When the next version replaced it. - `verifiedAt` ([`Date`](/docs/types.md#date)): When a person had last confirmed it against its source; null meant nobody had. - `verifiedBy` (`String`): Who had confirmed it. - `version` (`Int!`): Which version it was, counting from 1. - `weekendRule` ([`WeekendRule!`](/docs/types.md#weekendrule)): What it did with a date on a weekend or a holiday. ### SearchResults `object` Three answers to one search: parcels by number or address, units you hold property in, and documents by filename. Fields: - `documents` ([`[Document!]!`](/docs/types.md#document)): Documents whose filename matches. Empty, not an error, for a key without BILL_READ. - `jurisdictions` ([`[Jurisdiction!]!`](/docs/types.md#jurisdiction)): Units whose name matches and that the portfolio holds parcels in. Needs PARCEL_READ. - `parcels` ([`[Parcel!]!`](/docs/types.md#parcel)): Parcels whose number or address matches. Needs PARCEL_READ. ### StateCoverage `object` One state's (or DC's) units by coverage status. Fields: - `billers` ([`[BillingLevelCount!]!`](/docs/types.md#billinglevelcount)): The units that send a bill of their own, by level, most first. In Connecticut these are towns and cities, not counties. - `counts` ([`CoverageCounts!`](/docs/types.md#coveragecounts)): Every unit in the state. - `countyCounts` ([`CoverageCounts!`](/docs/types.md#coveragecounts)): The county-level units only: counties, parishes, independent cities and Alaska's boroughs. - `name` (`String!`): The state's name. - `state` (`String!`): The two-letter code. ### StateRollup `object` The portfolio in one state. Fields: - `assessedValue` ([`Money!`](/docs/types.md#money)): The total of their newest assessed values. - `parcelCount` (`Int!`): Parcels in the state. - `state` (`String!`): The two-letter state code. ### TaxAccount `object`, implements `Node`, needs `PARCEL_READ` One billing relationship on a parcel: the unit that sends a bill and the number it knows the property by. A California parcel has one, under its county; a Pennsylvania parcel has three, for its county, township and school district. Bills belong to accounts; assessments and appeals belong to the parcel. Fields: - `accountNumber` (`String!`): The unit's own identifier for the property: the APN in California, block and lot in New Jersey, the control number in Pennsylvania, the SBL in New York. - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When the account was recorded. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `jurisdiction` ([`Jurisdiction!`](/docs/types.md#jurisdiction)): The unit that bills the property under this account. - `origin` (`String!`): How the account came to be known: parcel (created with the parcel, for the unit that assesses it), import, api, fetch (a county record named the other units that bill the property), reference (the registry of taxing units), or a value beginning backfill for accounts recorded before origins were kept. - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel the account is on. - `status` ([`TaxAccountStatus!`](/docs/types.md#taxaccountstatus)): Whether the unit still bills the property under this account. ### TaxBill `object`, needs `BILL_READ` A bill as a taxpayer means it: one account's charges for one year, one bill type and one bill number, from the unit that sent it. Its installments are what reviews act on, and each has an id; the bill itself has a key. Fields: - `acceptedAutomatically` ([`AutomaticAcceptance`](/docs/types.md#automaticacceptance)): Set when the nightly fetch accepted this bill without a person, with the reason. Null when a person accepted it or it is not accepted. - `amountOutstanding` ([`OutstandingTotal`](/docs/types.md#outstandingtotal)): What is still owed on the bill, and how complete that figure is. Null while the bill is withheld, as totalBilled is. - `annualTotal` ([`Money`](/docs/types.md#money)): The annual total as the county stated it: the figure the charges and the installments are checked against. Null where the county printed none, and while withheld. - `assessmentYear` (`Int!`): The year of the assessed value the bill is based on. - `billNumber` (`String`): The county's own bill number. Null where the county publishes none. - `billType` ([`BillType!`](/docs/types.md#billtype)): Which roll the bill is on. - `charges` ([`[TaxCharge!]!`](/docs/types.md#taxcharge)): The county's charges for the year, which belong to the bill and not to one installment. They add up to chargesTotal. - `chargesTotal` ([`Money`](/docs/types.md#money)): The charges summed: what the year is made of. Null while withheld. - `installments` ([`[TaxBillInstallment!]!`](/docs/types.md#taxbillinstallment)): The bill's installments, first first. - `installmentsTotal` ([`Money`](/docs/types.md#money)): The installments summed: what is owed and when, as the county split the year, which may carry penalty a county folded into an installment (penaltyIncluded). Null while withheld. - `key` (`ID!`): Tells the bills of one parcel apart, each revision its own. Opaque and stable across requests; not an id that node or bill accepts. - `paidPerRecords` ([`Money`](/docs/types.md#money)): What the customer's own records say was paid on the whole bill: the sum over its installments. Null when no installment has anything on record. - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel the bill is for. - `payableYear` (`Int!`): The year the bill falls due. - `penaltyIncluded` ([`Money`](/docs/types.md#money)): Penalty a county folded into an installment's amount (penaltyBasis INCLUDED_IN_AMOUNT_DUE), summed over the installments. Already inside installmentsTotal and the balance, and never added again. Null when no installment carries one. - `retrieveIqCheck` ([`RetrieveIqCheck`](/docs/types.md#retrieveiqcheck)): Set while retrieve-IQ is checking this bill before the customer acts on it. Null otherwise. - `revision` (`Int!`): Zero for the bill as the unit first issued it. When the unit re-issues it with other charges (on a page that lists none, another total), or a person corrects a reading, the new figures are the next revision, waiting for review under a key of its own; the revision they replace is kept as evidence, SUPERSEDED or REJECTED, and counted nowhere. A change that leaves the charges as they were (a payment posted, interest grown, a date printed) updates the same revision. - `sourceDocument` ([`Document`](/docs/types.md#document)): The county page or uploaded file the bill was read from. - `status` ([`BillStatus!`](/docs/types.md#billstatus)): The bill's review status, taken from its installments: the one most in need of attention speaks for the bill. Never a payment status: amountOutstanding and paidPerRecords say what is known of payment. - `taxAccount` ([`TaxAccount!`](/docs/types.md#taxaccount)): The account the bill was sent under: which unit sent it, and the number it knows the property by. - `totalBilled` ([`Money`](/docs/types.md#money)): The sum of the installments, the same figure as installmentsTotal. Null, never "0.00", while the bill is withheld: the installments still show their figures, this does not add them up. - `validations` ([`[Validation!]!`](/docs/types.md#validation)): Every check run against this bill, across its installments: those still standing first, then warnings, then the ones a person or a later run settled. - `version` (`Int!`): Moves whenever anything about this bill changes: a decision, a figure, a date, a charge, its stated total. Every review mutation takes the version its caller read as expectedVersion, and is refused with CONFLICT when it has moved. Not the revision. - `withheld` (`Boolean!`): True while an unresolved ERROR check stands against the bill. A withheld bill's figures are shown on its installments for the reviewer and left out of every total until a person resolves the check or rejects the bill. - `withheldReason` (`String`): The codes of the checks that stand, comma separated, while withheld. Null otherwise. ### TaxBillInstallment `object`, implements `Node`, needs `BILL_READ` One installment of a bill: what is payable, when, and what is left. Reviews act on installments, so each has an id of its own. Fields: - `amountDue` ([`Money!`](/docs/types.md#money)): What the county asks for this installment. - `amountOutstanding` ([`Money`](/docs/types.md#money)): What is left to pay. Null when the payment figure or the penalty convention is unknown; never read a null as zero. - `amountPaid` ([`Money`](/docs/types.md#money)): What the county reports paid. Null when the county publishes no payment figure (Los Angeles and Orange do not), which is not the same as zero. - `delinquentAfter` ([`Date`](/docs/types.md#date)): The last day to pay before a penalty is added, which is the date the county warns taxpayers about. - `dueDate` ([`Date!`](/docs/types.md#date)): The date the installment falls due by statute (November 1 and February 1 in California). Not the last day to pay. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `installmentLabel` (`String!`): As the county labels it: "1st", "2nd", "Annual". - `installmentNo` (`Int`): Its position on the bill, 1 for the first. Null where the bill does not number it. - `paidPerRecords` ([`Money`](/docs/types.md#money)): What the customer's own records say was paid on this installment: payments less refunds, adjustments signed. Null when nothing is on record, which is not a paid figure of zero. Shown beside amountPaid, the county's figure, never in its place. - `paymentKnown` (`Boolean!`): Whether the county publishes a payment figure for this installment. - `payments` ([`[PaymentObservation!]!`](/docs/types.md#paymentobservation)): The customer's own payment records for this installment, oldest first. - `penalty` ([`Money`](/docs/types.md#money)): The penalty the county adds after delinquentAfter, where it publishes one. - `penaltyBasis` ([`PenaltyBasis`](/docs/types.md#penaltybasis)): Whether amountDue already includes the penalty or the penalty is added to it. Null where the county does not say. - `status` ([`BillStatus!`](/docs/types.md#billstatus)): The installment's review status. Never a payment status: amountPaid and paymentKnown carry the county's word, paidPerRecords the customer's own records. - `withheld` (`Boolean!`): True for every installment of a withheld bill (TaxBill.withheld). ### TaxCharge `object` One line on the county's bill. The lines describe the whole year, not any one installment. Fields: - `agencyPhone` (`String`): That agency's phone number, where the county prints it. - `amount` ([`Money!`](/docs/types.md#money)): The amount of the line for the year. - `chargeType` ([`ChargeType`](/docs/types.md#chargetype)): What kind of charge it is. Null where the county does not say; never guessed. - `description` (`String!`): The line as the county prints it. - `id` (`ID!`): The id of this record. Not a Node id: node does not accept it. - `levyingAgency` (`String`): The agency the charge is levied for, where the county names it. - `rate` (`String`): The rate the county prints for the line, where it prints one. ### Tenant `object`, implements `Node` An organisation: a firm that works for taxpayers, or a taxpayer whose parcels are held. Fields: - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `kind` (`String!`): agent_firm, a firm that works for taxpayers under engagements, or taxpayer, an organisation that holds property of its own. - `name` (`String!`): The organisation's name. ### UpsertParcelPayload `object` The parcel, and whether this call added it. Fields: - `created` (`Boolean!`): False when the parcel was already held; nothing changed. - `parcel` ([`Parcel!`](/docs/types.md#parcel)): The parcel, as held now. ### User `object`, implements `Node` A person at a firm, or the service user an API key acts as. Fields: - `email` (`String!`): The person's email address. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `name` (`String!`): The person's name, or the key's name for a service user. - `tenant` ([`Tenant!`](/docs/types.md#tenant)): The firm the person belongs to, never the client being acted for. ### Validation `object`, implements `Node`, needs `BILL_READ` One check run against one bill: what it expected, what it found, and whether a person resolved it or a later run cleared it, with everything that happened to it since. An unresolved, uncleared ERROR withholds the bill. Fields: - `clearedAt` ([`DateTime`](/docs/types.md#datetime)): When a later run of the check passed. The check stays as history. - `code` (`String!`): Which check it is, as a stable code: apn_mismatch, year_over_year_jump and so on. - `createdAt` ([`DateTime!`](/docs/types.md#datetime)): When the check first made the finding. - `expected` (`String`): What the check expected to find. - `history` ([`[ValidationEvent!]!`](/docs/types.md#validationevent)): Everything that happened to this check, oldest first: found, changed, resolved (who and why), reopened, cleared, found again. - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. - `installment` ([`TaxBillInstallment!`](/docs/types.md#taxbillinstallment)): The installment the check ran against. - `message` (`String!`): The finding, in words. - `observed` (`String`): What it found. - `resolutionNote` (`String`): The words of the resolution that stands now; null when none stands. Every resolution's words stay in history. - `resolvedAt` ([`DateTime`](/docs/types.md#datetime)): When a person accepted the discrepancy; null while no resolution stands. - `resolvedBy` ([`User`](/docs/types.md#user)): The person who accepted it. - `ruleVersion` (`String`): The version of the checks that made the finding; null for a finding made before versions were recorded. - `severity` ([`Severity!`](/docs/types.md#severity)): How much the finding matters. ### ValidationEvent `object`, needs `BILL_READ` One thing that happened to a check, with the check's severity and figures at that moment. Kept for good: a resolution a later run set aside stays here with its person and words. Fields: - `at` ([`DateTime!`](/docs/types.md#datetime)): When it happened. - `by` ([`User`](/docs/types.md#user)): The person, for RESOLVED; null for everything else. - `expected` (`String`): What the check expected to find at that moment. - `kind` ([`ValidationEventKind!`](/docs/types.md#validationeventkind)): What happened. - `note` (`String`): Their words, for RESOLVED. - `observed` (`String`): What it found at that moment. - `reconstructed` (`Boolean!`): Pieced together from the check and the activity trail when the history began, not written as it happened: its figures are the check's as they stood then. - `ruleVersion` (`String`): The version of the checks that ran; null where it was not recorded. - `severity` ([`Severity!`](/docs/types.md#severity)): The check's severity at that moment. ## Inputs ### AddressInput `input` The property's street address as you know it. Every field optional. A fetch fills in a blank street line from the unit's record and changes nothing you gave. Fields: - `city` (`String`): The city. - `line1` (`String`): The street address. - `line2` (`String`): A suite or unit, where there is one. - `postalCode` (`String`): The ZIP code. - `state` (`String`): The two-letter state code. The county's state when omitted. ### BillCorrectionInput `input` A reading corrected by hand: the installments to change, and the charges when they were misread too. The installments must add up to the charges, or the correction is refused. Fields: - `charges` ([`[ChargeCorrectionInput!]`](/docs/types.md#chargecorrectioninput)): Replaces the reading's charges when given; left out, they carry over. - `installments` ([`[InstallmentCorrectionInput!]!`](/docs/types.md#installmentcorrectioninput), required): The installments to change, each by its id. ### BillEntryInput `input` A bill entered by hand from its page: its year and type, its installments and the charges it lists. The installments must add up to the charges, or the entry is refused. Fields: - `assessmentYear` (`Int!`, required): The year of the assessed value the bill is based on. - `billNumber` (`String`): The county's own number for the bill, when it prints one. - `billType` ([`BillType!`](/docs/types.md#billtype), required): Which kind of bill it is. - `charges` ([`[ChargeCorrectionInput!]!`](/docs/types.md#chargecorrectioninput), required): The charges it lists for the year. - `installments` ([`[BillEntryInstallmentInput!]!`](/docs/types.md#billentryinstallmentinput), required): Its installments, as it prints them. ### BillEntryInstallmentInput `input` One installment as the bill prints it. Fields: - `amountDue` ([`Money!`](/docs/types.md#money), required): What the bill asks for it. - `delinquentAfter` ([`Date`](/docs/types.md#date)): The date after which the county adds a penalty, when the bill prints one. - `dueDate` ([`Date!`](/docs/types.md#date), required): When it is due. - `installmentNo` (`Int!`, required): Its number on the bill, from 1. ### BillInboxFilter `input` Which bills the inbox lists. Fields: - `jurisdictionIds` (`[ID!]`): Bills sent by any of these units. Narrower than ParcelFilter.jurisdictionIds: filtering by a school district returns that district's bills, not the county's and the township's for the same parcel. - `search` (`String`): Bills whose parcel number, street address, city or county bill number contains this text. - `view` ([`BillInboxView`](/docs/types.md#billinboxview)): WAITING when omitted. - `withheldOnly` (`Boolean`): Only bills an ERROR check stands against. ### ChargeCorrectionInput `input` One charge as the bill prints it. Fields: - `amount` ([`Money!`](/docs/types.md#money), required): What the bill charges for it. - `chargeType` ([`ChargeType`](/docs/types.md#chargetype)): What kind of charge it is, if you know. - `description` (`String!`, required): The charge as the bill names it: "General levy", "Flood control". ### InstallmentCorrectionInput `input` One installment of the bill with the figures to change. A field left out keeps what the reading had. Fields: - `amountDue` ([`Money`](/docs/types.md#money)): What the county asks for it. - `amountPaid` ([`Money`](/docs/types.md#money)): Null when the county publishes no payment figure. - `delinquentAfter` ([`Date`](/docs/types.md#date)): The date after which the county adds a penalty, when the bill prints one. - `dueDate` ([`Date`](/docs/types.md#date)): When it is due. - `installmentId` (`ID!`, required): The installment, as the bill lists it. ### ParcelFilter `input` Which parcels to list. Every condition given must hold. Fields: - `assessedValueMin` ([`Money`](/docs/types.md#money)): Parcels whose current total assessed value is at least this. - `hasOpenAppeal` (`Boolean`): True: parcels with an appeal at OPEN or FILED; false: parcels without one. - `jurisdictionIds` (`[ID!]`): Parcels assessed by, or billed by, any of these units. - `legalEntityIds` (`[ID!]`): Parcels held under any of these owners of record. - `search` (`String`): Parcels whose number or address contains this text. - `states` (`[String!]`): Parcels in any of these states, by two-letter code. - `status` ([`ParcelStatus`](/docs/types.md#parcelstatus)): Parcels at this status. ### ParcelImportInput `input` A whole spreadsheet at once, under one owner of record: an existing one by id, or one found or created by name. Every row is checked before anything is written, and the accepted rows land together; dryRun checks and writes nothing. Fields: - `dryRun` (`Boolean`, default false): True to check the rows and write nothing. - `legalEntityId` (`ID`): An existing owner of record, by id. Either this or legalEntityName. - `legalEntityName` (`String`): An owner of record by name, found or created. Either this or legalEntityId. - `rows` ([`[ParcelImportRowInput!]!`](/docs/types.md#parcelimportrowinput), required): The rows, at most 500. ### ParcelImportRowInput `input` One row of a parcel spreadsheet: the county and the parcel number, and optionally the state, the street address, city and ZIP code. A row that names no state is California's. Fields: - `city` (`String`): The city. - `county` (`String!`, required): The county by name, as people write it. - `parcelNumber` (`String!`, required): As the county writes it. - `situsLine1` (`String`): The street address. - `state` (`String`): The county's two-letter state. California when left out. - `zip` (`String`): The ZIP code. ### ParcelInput `input` One parcel to add. Name the unit that assesses it by jurisdictionId, or name its county, with the state outside California; exactly one of the two. Fields: - `county` (`String`): The county by name, as people write it: "Los Angeles", with or without "County", "Orleans Parish", "Richmond city". - `jurisdictionId` (`ID`): The id of the unit that assesses the parcel, from jurisdictions. - `legalEntityId` (`ID!`, required): The owner of record to hold it under, from legalEntities. - `parcelNumber` (`String!`, required): As the county writes it. - `situs` ([`AddressInput`](/docs/types.md#addressinput)): The street address, if known. - `state` (`String`): The county's two-letter state, when the county is named. California when left out. - `useCode` (`String`): The county's use code, if known. ### ParcelOrder `input` How to order the parcel list. Fields: - `direction` ([`OrderDirection!`](/docs/types.md#orderdirection), required): Which way. - `field` ([`ParcelOrderField!`](/docs/types.md#parcelorderfield), required): What to order by. ### PaymentImportInput `input` A whole list of payments at once. Every row is checked, the good ones land as one transaction, and a row already recorded is counted, not recorded twice; dryRun checks and writes nothing. Fields: - `dryRun` (`Boolean`): True to check every row and write nothing. - `rows` ([`[PaymentImportRowInput!]!`](/docs/types.md#paymentimportrowinput), required): The payments, one a row. ### PaymentImportRowInput `input` A row of a payment spreadsheet: which parcel (by number, with the county when the number is held in more than one), which year and installment, how much and when. Fields: - `amount` ([`Money!`](/docs/types.md#money), required): How much: positive for a payment or a refund, signed for an adjustment. - `assessmentYear` (`Int!`, required): The assessment year of the bill paid. - `county` (`String`): The county by name. Needed only when the portfolio holds that parcel number in more than one county. - `installmentNo` (`Int!`, required): Which installment of that bill, from 1. - `kind` ([`PaymentKind`](/docs/types.md#paymentkind)): PAYMENT when left out. - `paidOn` ([`Date!`](/docs/types.md#date), required): The day the money moved. - `parcelId` (`ID`): A person's choice of parcel for a row whose number did not match one exactly, usually from the candidates a check offered. The import's trail records the row, the number it gave, the parcel chosen and how the two numbers relate. - `parcelNumber` (`String!`, required): As the county writes it. - `reference` (`String`): A check number, a confirmation, a ledger line. - `state` (`String`): The county's two-letter state; California when left out. ### ReportFilter `input` Which parcels the report covers: the conditions of ParcelFilter apart from assessedValueMin, with status as text, or named appeals. Omitted, the whole portfolio. Fields: - `appealIds` (`[ID!]`): Only these appeals and the parcels they are on: the evidence pack for one appeal is APPEAL_EVIDENCE_PACK with one id here. Each must be an appeal you can read; at most 200. - `hasOpenAppeal` (`Boolean`): True: parcels with an appeal at OPEN or FILED; false: parcels without one. - `jurisdictionIds` (`[ID!]`): Parcels assessed by, or billed by, any of these units. - `legalEntityIds` (`[ID!]`): Parcels held under any of these owners of record. - `search` (`String`): Parcels whose number or address contains this text. - `states` (`[String!]`): Parcels in any of these states, by two-letter code. - `status` (`String`): Parcels at this status: a ParcelStatus value, such as ACTIVE. ### ReportRuleInput `input` What is wrong with a rule or a requirement, in your words. The server records what the screen showed for that rule and year itself. Fields: - `assessmentYear` (`Int!`, required): The assessment year the rule was shown for. - `evidenceUrl` (`String`): Where you saw the right value: an http or https link. - `jurisdictionId` (`ID!`, required): The unit whose rule is wrong (a Jurisdiction id). - `problem` (`String!`, required): What is wrong, up to 2,000 characters. - `requirementCode` (`String`): For a REQUIREMENT: its code, as appealRequirements gives it. - `subject` ([`RuleReportSubject!`](/docs/types.md#rulereportsubject), required): What is wrong: one kind of dated rule, or a requirement. - `suggested` (`String`): What it should say, if you know: up to 500 characters. ### StartDocumentUploadInput `input` What is about to be uploaded: the link is bound to these, and the bytes must agree with them. Fields: - `byteSize` (`Int!`, required): Its exact size in bytes. - `filename` (`String!`, required): Its name, with its extension: .pdf, .csv or .xlsx. - `kind` ([`DocumentKind!`](/docs/types.md#documentkind), required): What the document is, as it will be filed on the parcel. - `parcelId` (`ID!`, required): The parcel the document belongs to. ## Enums ### ApiKeyStatus `enum` Whether a key works. Values: - `ACTIVE`: It works. - `EXPIRED`: Its last day has passed. - `REVOKED`: A person ended it. The record stays. ### AppealAction `enum` The moves updateAppealStatus makes. A decision is recorded with recordAppealOutcome instead. Values: - `FILE`: Mark it filed, with the date. - `REOPEN`: Reopen a withdrawn appeal. - `WITHDRAW`: Withdraw it. ### AppealRequirementTopic `enum` What part of a filing a requirement is about. Values: - `AGENT`: Filing for the owner. - `BOARD`: Who hears the appeal and where it is filed. - `CONTENT`: What the application must state. - `FILING`: When a filing counts as on time. - `FORM`: The application. - `OTHER_DEADLINE`: Filing periods the dated rules do not cover, such as a supplemental assessment's. - `SIGNATURE`: How it is signed. ### AppealStatus `enum` Where an appeal stands. Values: - `DECIDED`: Decided; the outcome is recorded. Final. - `FILED`: Filed with the board, awaiting a decision. - `OPEN`: Recorded, not yet filed. - `WITHDRAWN`: Withdrawn before a decision. It can be reopened. ### BillDelivery `enum` How a unit makes its bill available. Values: - `EMAIL`: Sent by email. Reserved: no unit is recorded with it yet. - `MAILED_PDF`: Mailed on paper. Reserved: no unit is recorded with it yet. - `NONE`: No bill: the unit publishes none online, or sends none of its own. - `PORTAL_SCRAPE`: Published on the unit's own website, where it is fetched every night. - `SFTP_FEED`: Delivered as a file feed. Reserved: no unit is recorded with it yet. - `UPLOAD`: Supplied by the firm as a file. Reserved: no unit is recorded with it yet. ### BillEntryOutcome `enum` What became of a bill entered by hand. Values: - `DUPLICATE`: The same bill is already on file; nothing new was stored. - `EVIDENCE_ONLY`: Kept as the person entered it, and not a bill: a check found something wrong (the message says what). - `STORED`: A bill waiting in the inbox for review. ### BillInboxView `enum` Which bills the inbox lists. Values: - `DECIDED`: Bills a person accepted or rejected, the newest arrival first, so a decision can be found again. - `WAITING`: Bills still waiting on a decision (NEEDS_REVIEW or DISPUTED), the oldest arrival first. The default. ### BillStatus `enum` Where a bill's reading stands in review, and nothing about payment. Every fetched bill starts at NEEDS_REVIEW. What the county publishes about payment is on each installment (amountPaid, paymentKnown, amountOutstanding), with paymentKnown false where it publishes none; what the customer's own records say is beside it (payments, paidPerRecords). Neither moves the status, and the status moves neither. Values: - `CLOSED`: Never returned. - `DISPUTED`: Flagged for the client, with a note. - `INGESTED`: Reserved: every bill arrives at NEEDS_REVIEW today. - `NEEDS_REVIEW`: Waiting for a person's decision: where every fetched, uploaded or corrected reading lands. - `PAID`: Never returned. - `REJECTED`: Rejected by a reviewer as a wrong reading of the bill. Final, and left out of every total and date: a later fetch does not reopen it. - `SUPERSEDED`: A revision the county replaced with a newer one, kept as evidence. Left out of every total and date. - `VALIDATED`: Accepted by a reviewer. ### BillType `enum` Which roll a bill is on, as the county classifies it. Values: - `ESCAPE`: A bill for value that escaped assessment in an earlier year. - `REDEMPTION`: A bill to redeem earlier years' unpaid taxes. - `SECURED`: The annual bill on real property. - `SUPPLEMENTAL`: A bill for a change in value part way through the year, after a sale or new construction. - `UNSECURED`: A bill on property that is not land or buildings, such as equipment, fixtures or a boat. ### ChargeType `enum` What kind of charge a line on the bill is, where the county says. Values: - `AD_VALOREM`: Tax on the assessed value at the general rate. - `DIRECT_CHARGE`: A flat charge from a district or agency, not based on value. - `FEE`: A fee added to the bill. - `PENALTY_AND_COST`: Penalties and costs added for late payment. - `SPECIAL_ASSESSMENT`: A charge for a local improvement, levied on the parcels that benefit from it. - `VOTER_APPROVED_DEBT`: Tax to repay bonds the voters approved. ### CoverageStatus `enum` Whether a unit's bills can be fetched, from the best of its sites. Earlier values take precedence. Values: - `ASSESSMENT_ONLY`: The unit sends no bill of its own. - `CLOSED`: The unit's site does not allow automated access, so its bills cannot be fetched. The reason is recorded. - `COVERED`: Bills are fetched from the unit's own site every night. - `NOT_SURVEYED`: Not surveyed yet. - `NO_PORTAL`: The unit publishes no bill online. - `OTHER`: A site that publishes a balance but no bill document, or an image-only bill. - `PORTAL_FOUND`: The unit publishes bills online; support for its site is not built yet. - `READER_READY`: The unit's site is supported and waits for a final live check. - `RETIRED`: The unit's site was retired. ### DeadlineKind `enum` What a date is. Values: - `APPEAL_CLOSE`: The last day an appeal of the year can be filed. - `APPEAL_OPEN`: The first day an appeal of the year can be filed. - `PAYMENT_DELINQUENT`: The last day to pay an installment before a penalty is added. - `PAYMENT_DUE`: The date an installment falls due. ### DocumentKind `enum` What a document is. Values: - `APPEAL_DECISION`: A decision on an appeal. - `ASSESSMENT_NOTICE`: A notice of assessed value. - `CORRESPONDENCE`: A letter or other correspondence about the parcel. - `RECEIPT`: A payment receipt. - `TAX_BILL`: A tax bill, as the county published it or as it was uploaded. ### ExtractionState `enum` How far the reading of a document has got. Values: - `CONFIRMED`: Read and confirmed by a person. Reserved: not produced today. - `EXTRACTED`: Read; its figures are on the bill. - `FAILED`: Could not be read; the document needs a look. - `MATCH_FAILED`: Read, but what it says could not be matched to a parcel. Reserved: not produced today. - `OCR_RUNNING`: Being read. Reserved: not produced today. - `QUEUED`: Waiting to be read. Reserved: not produced today. ### FeedOutcome `enum` How one night of the feed ended. Values: - `DELIVERY_FAILED`: The files were produced but could not be delivered. - `EXPORT_FAILED`: The files could not be produced. - `PARTIAL`: The files were produced and delivered, but some parcels could not be fetched that night. - `RUNNING`: Still running. - `SUCCESS`: The client's fetch finished without an error, and the files were produced and delivered. - `SWEEP_FAILED`: The night's fetch failed before any file was produced. ### IngestOutcome `enum` How one attempt to fetch a bill from a county ended. Values: - `BLOCKED`: The county's site refused the request. - `ERROR`: The attempt failed for another reason. - `NOT_FOUND`: The county answered and had no bill for the parcel. - `PARSE_ERROR`: The county answered with a page that could not be read. - `SUCCESS`: A bill was fetched. - `TIMEOUT`: The county's site did not answer in time. ### OrderDirection `enum` Which way to order. Values: - `ASC`: Lowest, earliest or A first. - `DESC`: Highest, latest or Z first. ### ParcelOrderField `enum` What to order the parcel list by. Values: - `ASSESSED_VALUE`: The current assessment's total value. - `JURISDICTION`: The name of the unit that assesses the parcel. - `NEXT_DUE_DATE`: The next payment date. - `PARCEL_NUMBER`: The parcel number, as text. ### ParcelStatus `enum` Where a parcel stands in the portfolio. Values: - `ACTIVE`: Held and tracked. The status every parcel starts in. - `DISPOSED`: Sold or otherwise no longer held; kept for its history. - `EXEMPT`: Exempt from property tax. - `PENDING_ASSESSMENT`: Held, with an assessment still to come. ### PaymentKind `enum` What an entry in the customer's own payment records is. Values: - `ADJUSTMENT`: A signed correction of an earlier entry, the way a wrong entry is reversed. - `PAYMENT`: Money paid to the unit. - `REFUND`: Money the unit paid back. ### PaymentSource `enum` How an entry in the payment records was made. Values: - `CUSTOMER_IMPORT`: It came in with a list of payments (importPayments). - `MANUAL`: A person recorded it, one at a time (recordPayment). ### PenaltyBasis `enum` How the county states a penalty against the amount due. Values: - `ADDED_TO_AMOUNT_DUE`: The penalty is added on top of the amount due once the date passes. - `INCLUDED_IN_AMOUNT_DUE`: The amount due already includes the penalty. ### PortalStatus `enum` The standing of one of a unit's sites. Values: - `ASSESSMENT_ONLY`: The unit sends no bill of its own. - `CANDIDATE`: Known, and not yet checked. - `COVERED`: Bills are fetched from it. - `COVERED_AMOUNT_ONLY`: A balance is fetched from it; the site publishes no bill document. - `COVERED_NEEDS_EXTRACTOR`: Bills are fetched from it as images, which are read on request. - `NO_PORTAL`: The unit publishes no bill online. - `RETIRED`: The site was retired. - `UNREACHABLE`: Automated access is not possible; reason says why. ### ReportCategory `enum` How the reports are grouped. Values: - `ACCOUNTING`: Figures for the books. - `APPEALS`: Appeals and their outcomes. - `COMPLIANCE`: Dates, bills and what stands against them. - `PORTFOLIO`: What is held and what it is worth. ### ReportFormat `enum` The file a report is produced as. Every report comes as CSV, XLSX and PDF; reportCatalog lists the formats of each. Values: - `CSV`: Comma-separated text, one header row. - `PDF`: A PDF for reading and printing. - `XLSX`: An Excel workbook. - `ZIP`: The appeal evidence pack alone: the pack as a PDF and a CSV, with the documents it lists beside them, one folder per appeal, and an index of what is there and what is not. ### ReportJobStatus `enum` Where a requested report is. Values: - `DONE`: Ready: downloadUrl fetches the file. - `EXPIRED`: The file has been removed. Request the report again. - `FAILED`: Could not be produced; error says why. - `QUEUED`: Waiting to be produced. - `RUNNING`: Being produced. ### ReportKind `enum` The reports that can be produced. reportCatalog describes each one and lists its columns. Values: - `APPEAL_EVIDENCE_PACK`: For each appeal: what was asked against what and where it stands, the certified value and its revisions, the original documents and how each was read and reviewed, every reading of the year’s bills, the corrections, the checks and who accepted each, and the trail with the person and the firm, as the records hold them. A trail too long to carry whole ends with a line saying where it was cut and how much is not in the pack. - `APPEAL_OUTCOMES_AND_SAVINGS`: Every appeal on record: the certified value, what was asked, what was decided, the reduction realised against the reduction requested, and the tax saved where known. - `ASSESSED_VALUE_ROLL_FORWARD`: Every parcel's newest two assessment years side by side: the change, the change as a percentage, and a flag at 10% or more. - `BILL_INGESTION_AUDIT`: Every installment we hold, which unit billed it, where its page came from, how it was read and by whom it was reviewed, and how many checks stand against it. - `DEADLINE_EXPOSURE_REGISTER`: Every payment and appeal date in the next 120 days with the balance at stake, or why the balance is not known, the undated windows last with their reason. The jurisdiction column is the unit the date belongs to: the one that sent the bill for a payment, the one that hears the appeal for a window. - `TAX_LIABILITY_FORECAST`: Next year's installments per parcel and billing unit, projected from the newest assessed value at the effective rate the last billed year paid to that unit, split the way that year was split. ### RetrieveIqCheckReason `enum` Why retrieve-IQ is checking a bill before the customer acts on it. Values: - `CHECK_FAILED`: A check on the reading failed (the figures do not add up, the parcel differs, a total moved tenfold). - `READER_PAUSED`: This county's reader is paused after a wrong bill in retrieve-IQ's hand-checked sample. - `REPORTED`: Someone reported this automatically accepted bill as wrong. - `ZERO_TOTAL`: A $0 bill, which is never accepted automatically. ### RuleKind `enum` Which dated rule: the appeal window, the notice of value, the informal review, or the valuation date. Values: - `APPEAL_CLOSE`: The last day of the regular appeal filing window. - `APPEAL_OPEN`: The first day of the regular appeal filing window. - `ASSESSMENT_DATE`: The valuation date the assessment is made as of. - `INFORMAL_REVIEW_CLOSE`: The last day to ask the assessor for an informal review. - `NOTICE_EXPECTED`: When the assessor mails the notice of value. ### RuleReportStatus `enum` Where a report stands with the people who maintain the rules. Values: - `DECLINED`: They checked and the rule stands; resolution says why. - `FIXED`: The rule was corrected. - `OPEN`: Waiting for the people who maintain the rules. ### RuleReportSubject `enum` What the report is about: one kind of dated rule, or a filing requirement. Values: - `APPEAL_CLOSE`: The day the appeal window closes. - `APPEAL_OPEN`: The day the appeal window opens. - `ASSESSMENT_DATE`: The valuation date. - `INFORMAL_REVIEW_CLOSE`: The last day to ask for an informal review. - `NOTICE_EXPECTED`: When the notice of value is mailed. - `REQUIREMENT`: A filing requirement, named by its code. ### RuleStatus `enum` Whether a rule gives a date for the year, and if not, why not. Only DATED and BOUND carry a date, and neither is ever invented. Values: - `AWAITING_EVENT`: The rule counts from an event (a notice mailed, a roll published) whose date is not on record yet. - `BOUND`: One side of a later-of or earlier-of rule is an event whose date is not on record, so the date is a floor or a ceiling, not the deadline. - `DATED`: The rule gives this date. - `NOT_RECORDED`: No rule of this kind is recorded for the unit, its parent or its state. - `SET_LOCALLY`: The date is set locally each year, and this year has not been recorded. - `UNREADABLE`: A rule is recorded but cannot be worked out, or names a day that is not on the calendar. ### Scope `enum` What a key or an engagement may do. A write scope does not include the matching read scope. Values: - `ADMIN`: Manage the firm itself. Held by people in the app, never by a key. - `APPEAL_WRITE`: Record appeals and update them. - `BILL_READ`: Read tax bills, the checks run against them, the documents behind them and the nightly fetch status. - `BILL_REVIEW`: Accept, flag and reject bills, resolve their checks, and take a decision back. - `PARCEL_READ`: Read parcels, their assessments, the units that assess and bill them, deadlines and calendar feeds. - `PARCEL_WRITE`: Add and import parcels. - `REPORT_READ`: Request and download reports, and read the portfolio summary. ### Severity `enum` How much a check's finding matters. Values: - `ERROR`: Withholds the bill: it cannot be accepted until a person resolves the check or a later run clears it. - `INFO`: For information; nothing to do. - `WARNING`: Worth a look; the bill can still be accepted. ### TaxAccountStatus `enum` Whether the unit still bills the property under this account. Values: - `ACTIVE`: The unit still bills the property under this number. - `CLOSED`: It no longer does; the bills already held stay. ### UnreachableReason `enum` Why a site cannot be fetched from. Values: - `BOT_BLOCK_HEADFUL_FAILS`: The site blocks automated visitors, even a full browser. - `CAPTCHA`: The site asks every visitor to prove they are a person before it shows a bill. - `DATACENTER_IP_CHALLENGED`: The site challenges visitors from data centres. - `LOGIN_WALL`: The site requires an account. - `OFFLINE`: The site was offline when checked. - `PAYWALL`: The site charges per lookup. - `ROBOTS_DISALLOW`: The site's published rules for automated visitors do not allow it. - `TERMS_FORBID`: The unit's own terms do not allow automated access. ### ValidationEventKind `enum` What happened to a check. Values: - `CHANGED`: A later run of the standing check found other figures. - `CLEARED`: A later run passed. - `FOUND`: The check first made the finding. - `FOUND_AGAIN`: The check made the finding again after it had passed. - `REOPENED`: A later run found other figures than the ones accepted, so the resolution no longer covers them. - `RESOLVED`: A person accepted the discrepancy. ### WeekendRule `enum` What happens to a date that falls on a weekend or a holiday. Values: - `NEXT_BUSINESS_DAY`: A date on a Saturday, Sunday or federal holiday moves to the next business day. State holidays are not counted, so a date can show one business day early, the safe direction. - `NONE`: The date stands whatever day it falls on. ## Interfaces ### Node `interface` Anything with an id of its own. Any Node can be fetched again by that id with node or nodes. Fields: - `id` (`ID!`): The id: opaque, stable, and what node, nodes and every argument that takes an id accept. ## Scalars ### Date `scalar` A calendar date, YYYY-MM-DD. No time, no timezone. ### DateTime `scalar` An instant, ISO 8601 in UTC. ### JSON `scalar` Arbitrary JSON, passed through untouched. ### Money `scalar` A monetary amount in major units with two decimals, e.g. "71486.32". USD implied.