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¶
- Omitting the mask on Update replaces the ENTIRE document content — use with care
- Empty mask (
{"paths": []}) is a no-op — nothing gets updated - Nested paths use dots:
content.invoice.legal_monetary_total.payable_amount - Repeated fields are replaced entirely (not merged) when their parent is in the mask
- Map fields follow the same replace semantics
- 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.