Skip to content

Field Masks

Invora uses google.protobuf.FieldMask for two purposes: 1. Read masks — control which fields are returned (reduce payload size) 2. Update masks — control which fields are modified (partial updates)

Read Masks

Pass a mask field on Get and List requests to receive only specific fields.

Example: List documents, only return id + state + type

{
  "filter": {},
  "pagination": {"pageSize": 20},
  "mask": {"paths": ["id", "edit_state", "document_type", "prefix", "sequence_id"]}
}

Response Document objects only populate the requested fields. Unrequested fields are zero-valued (empty string, 0, null).

Common patterns

Use Case Mask Paths
Dashboard list id, document_type, edit_state, prefix, sequence_id, frozen_at, branch_id
Status check id, edit_state, regulation_metadata
Full document Omit mask entirely (all fields returned)
Regulation only regulation_metadata

Get with mask (skip heavy UBL content)

{
  "key": "INV-001",
  "mask": {"paths": ["edit_state", "regulation_metadata", "document_type", "frozen_at"]}
}

This skips the full UBL content and xml_content fields — useful when you only need metadata.

Update Masks

Pass a mask field on Update requests. Only fields listed in the mask are modified; all other fields remain unchanged.

Example: Update only the customer party on an invoice

{
  "key": "INV-001",
  "concurrencyStamp": "abc123",
  "mask": {"paths": ["content.invoice.accounting_customer_party"]},
  "changes": {
    "content": {
      "invoice": {
        "accountingCustomerParty": {
          "party": {
            "partyName": [{"name": {"value": "Updated Customer Name"}}]
          }
        }
      }
    }
  }
}

Rules

  1. Omitting the mask on Update replaces the ENTIRE document content — use with care
  2. Empty mask ({"paths": []}) is a no-op — nothing gets updated
  3. Nested paths use dots: content.invoice.legal_monetary_total.payable_amount
  4. Repeated fields are replaced entirely (not merged) when their parent is in the mask
  5. Map fields follow the same replace semantics
  6. Paths use proto field names (snake_case), not JSON names (camelCase)

Settings partial update

{
  "mask": {"paths": ["pdf", "default_currency"]},
  "changes": {
    "pdf": {"showLogo": true, "showQrCode": true},
    "defaultCurrency": "SAR"
  }
}

Only pdf and default_currency are updated. Prefixes, regulation config, etc. remain untouched.

Proto field names vs JSON names

Field masks always use proto field names (snake_case), even when the request body uses JSON camelCase transcoding:

Proto field JSON field Mask path
edit_state editState edit_state
regulation_metadata regulationMetadata regulation_metadata
document_type documentType document_type
sequence_id sequenceId sequence_id
xml_content xmlContent xml_content
freeze_immediately freezeImmediately freeze_immediately

Streaming with masks

ListStream and GetStream RPCs also accept masks. The mask applies to every event in the stream — you can't change the mask mid-stream. Open a new stream to change the projection.