gRPC & JSON Transcoding¶
Every Invora API is defined once as a gRPC service and exposed over two interchangeable protocols:
- REST / JSON — ordinary HTTPS requests with JSON bodies. This is what every guide uses, and what you get by calling the gateway with
curl. - gRPC — the canonical binary protocol (HTTP/2) for high-throughput, server-to-server integrations, with generated typed clients.
Both speak to the same backend; the JSON surface is produced by gRPC-JSON transcoding (google.api.http annotations on each RPC). This page is the canonical reference for how the gRPC contract maps to the JSON you send and receive — field names, scalar types, dates, decimals, and enums.
Base URLs¶
| Environment | REST / gRPC gateway | Auth issuer |
|---|---|---|
| Production | https://gateway.invora.app |
https://auth.invora.app |
| Staging | https://stg-gateway.invora.app |
https://stg-auth.invora.app |
gRPC uses the same host on port 443 over TLS (HTTP/2). Every example below uses the production host; swap it for stg-gateway.invora.app to run against Staging.
Field names are camelCase¶
Proto fields are snake_case; the JSON surface is camelCase. The transcoder converts automatically — always send and read camelCase over JSON.
Proto (snake_case) |
JSON (camelCase) |
|---|---|
freeze_immediately |
freezeImmediately |
concurrency_stamp |
concurrencyStamp |
currency_code |
currencyCode |
payment_means_code |
paymentMeansCode |
source_document_key |
sourceDocumentKey |
Scalar & well-known types¶
The transcoder follows the standard proto3 JSON mapping. The cases worth memorizing:
| Proto type | JSON representation | Example |
|---|---|---|
string, bool |
as-is | "INV-001", true |
int32, enum value |
see below | |
int64 / uint64 |
string (avoids 53-bit precision loss) | "43200" |
google.protobuf.Timestamp |
RFC 3339 / ISO-8601 string, UTC Z |
"2026-05-31T10:00:00Z" |
google.type.Date |
object with year / month / day |
{"year": 2026, "month": 5, "day": 31} |
google.type.TimeOfDay |
object with hours / minutes / seconds |
{"hours": 14, "minutes": 30} |
google.protobuf.StringValue (wrapper) |
the bare value, not {"value": …} |
"Acme" (or null when unset) |
google.protobuf.Int32Value (wrapper) |
the bare number | 42 (or null) |
Wrapper types unwrap
Optional scalars modelled with the google.protobuf.*Value wrappers serialize to the bare value, not an object. Send "name": "Acme", not "name": {"value": "Acme"}. They accept null for "unset".
Dates are objects, not strings
google.type.Date and google.type.TimeOfDay are ordinary messages, so they serialize as JSON objects ({"year": …} / {"hours": …}). Only date-time values (google.protobuf.Timestamp) serialize as an ISO-8601 string. When a timezone is omitted, UTC is assumed; timestamps always end with Z.
Decimal values are {units, nanos}¶
Every monetary amount, quantity, and rate is an exact decimal — a JSON object with an integer units part and a fractional nanos part (billionths, 10⁻⁹), so there is never any floating-point rounding error:
| Decimal | JSON |
|---|---|
100 |
{"units": 100, "nanos": 0} |
100.50 |
{"units": 100, "nanos": 500000000} |
0.6789 |
{"units": 0, "nanos": 678900000} |
15 (a 15% rate) |
{"units": 15, "nanos": 0} |
units and nanos are both numbers (not strings); nanos is in the range 0–999999999 and must share the same sign as units. Never send a floating-point amount.
Enums are full string identifiers¶
Enum-valued fields take the full, prefixed string identifier — never an integer and never the bare suffix:
Use EDIT_STATE_FROZEN, not FROZEN. Other examples you will see: PLAN_INTERVAL_MONTHLY, EVENT_TYPE_INVOICE_CREATED, SORT_DIRECTION_DESCENDING, CONNECTED_BUSINESS_STATUS_ACTIVE. The accepted values for each field are listed on that field in the API reference.
Optional & repeated fields¶
Optional fields are omitted when unset (or sent as null). Empty repeated fields are returned as empty arrays (e.g. "invoiceAllowances": []) even when you did not send them.
Calling over REST / JSON¶
curl -X POST https://gateway.invora.app/api/v1/simple/invoices/list \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"pagination": {"limit": "10"}}'
Calling over gRPC¶
The same services are reachable as native gRPC on gateway.invora.app:443 (TLS, HTTP/2).
Proto modules (Buf Schema Registry)¶
The contract is published as seven modules on the Buf Schema Registry:
| Module | BSR reference | Contents |
|---|---|---|
| Common | buf.build/invora/common |
Shared document model and value types |
| Simple | buf.build/invora/simple |
The ergonomic invoice / credit-note / debit-note surface (invora.simple.*.v1) |
| Invoicing | buf.build/invora/invoicing |
Full UBL Documents API, parties, branches, settings, regulations |
| Billing | buf.build/invora/billing |
Plans, subscriptions, usage, wallets, analytics |
| Identity | buf.build/invora/identity |
Registration and connected businesses |
| Admin | buf.build/invora/admin |
Platform-administration services |
| UBL 2.1 | buf.build/invora/ubl-2-1 |
OASIS UBL 2.1 component definitions |
Code generation¶
Generate a typed client in any language straight from the registry:
plugins:
- remote: buf.build/protocolbuffers/csharp
out: gen
- remote: buf.build/grpc/csharp
out: gen
Metadata (headers)¶
gRPC uses metadata in place of HTTP headers:
| Metadata key | Value |
|---|---|
authorization |
Bearer <access_token> |
x-zitadel-orgid |
Target organization ID, for multi-org callers (see Authentication) |
Server reflection¶
Reflection is enabled on every environment, so grpcurl and Evans work without local protos:
grpcurl -H "Authorization: Bearer $TOKEN" \
gateway.invora.app:443 list
grpcurl -H "Authorization: Bearer $TOKEN" \
gateway.invora.app:443 \
invora.simple.invoices.v1.SimpleInvoiceService/List
API versioning¶
The version lives in both the proto package and the URL path — invora.simple.invoices.v1 ↔ /api/v1/..., invora.documents.v2 ↔ /api/v2/.... Breaking changes get a new major version; non-breaking additions (new fields, new RPCs) are made in place.
Related¶
- Getting started — environments and your first request.
- Authentication — tokens, scopes, gRPC metadata.
- List & filtering — list shape, filters, sorting, pagination.
- Field masks — partial reads and writes with the
maskstring. - Entity versioning — optimistic concurrency with
concurrencyStamp. - Error handling — status codes and structured error details.