> ## Documentation index
> Fetch the complete index at: /llms.txt
> Use it to discover every page before exploring further.

# 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
    }
  }
}
```
