> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# gRPC

> The 17 gRPC services StateSet exposes — the shared vocabulary, connection settings, and the two places gRPC behaves differently from REST.

# gRPC

StateSet exposes 17 gRPC services alongside the REST API, covering the same commerce domains.
Reach for gRPC when you're calling service-to-service and want a typed contract and lower
per-call overhead than JSON over HTTP.

<Warning>
  gRPC is **not** a drop-in mirror of REST. Two differences will bite you if you assume otherwise:

  * **Pagination is page-based** (`page`, `per_page`), not cursor-based like the REST endpoints.
  * **Money is an integer in minor units** — `Money { currency: "USD", amount: 1099 }` is $10.99, not
    $1,099.

  Both are covered below.
</Warning>

## Connecting

The gRPC server listens on its own port — by default **the HTTP port plus one**, overridable with
`grpc_port`.

```bash theme={null}
grpcurl -plaintext localhost:8081 list
```

Gzip compression is enabled in both directions on every service, so a client that negotiates gzip
gets it for free.

| Setting                                 | Purpose                                              |
| --------------------------------------- | ---------------------------------------------------- |
| `grpc_port`                             | Listen port. Defaults to `port + 1`                  |
| `grpc_concurrency_limit_per_connection` | Max in-flight requests per connection (floored at 1) |
| `grpc_timeout_secs`                     | Server-side request timeout. `0` disables            |
| `grpc_tcp_keepalive_secs`               | TCP keepalive. `0` disables                          |
| `grpc_http2_keepalive_interval_secs`    | HTTP/2 ping interval. `0` disables                   |
| `grpc_http2_keepalive_timeout_secs`     | How long to wait for a keepalive ack                 |

<Tip>
  Set the HTTP/2 keepalive interval if your clients sit behind a load balancer that reaps idle
  connections. Without it, a long-lived channel can be silently dropped and the next call fails rather
  than reconnecting cleanly.
</Tip>

Every request is assigned an `x-request-id` if it doesn't carry one, and that ID is propagated to
the response — the same correlation identifier the REST API uses. Log it.

## The shared vocabulary

Four messages in `stateset.common` are used across every service. Get these right once.

```protobuf theme={null}
package stateset.common;

message Money {
  string currency = 1;  // ISO 4217, e.g. "USD"
  int64  amount   = 2;  // smallest units — cents for USD
}

message Address {
  string street_line1 = 1;
  string street_line2 = 2;  // optional
  string city         = 3;
  string state        = 4;
  string country      = 5;  // ISO 3166-1 alpha-2, e.g. "US"
  string postal_code  = 6;
}

message PaginationRequest {
  int32 page     = 1;  // 1-based
  int32 per_page = 2;
}

message PaginationResponse {
  int32 total_items      = 1;
  int32 total_pages      = 2;
  int32 current_page     = 3;
  int32 items_per_page   = 4;
  bool  has_next_page    = 5;
  bool  has_previous_page = 6;
}
```

<Warning>
  `Money.amount` is an **`int64` in the currency's smallest unit**. Sending `10.99` is not possible —
  the field is an integer — and sending `1099` while thinking in dollars overcharges by 100×. Convert
  at the boundary and assert on the result.
</Warning>

`PaginationRequest.page` is **1-based**. Page `0` is not the first page.

## Services

| Service                | Package                    | RPCs |
| ---------------------- | -------------------------- | ---- |
| `OrderService`         | `stateset.order`           | 4    |
| `InventoryService`     | `stateset.inventory`       | 6    |
| `ProductService`       | `stateset.product`         | 5    |
| `CustomerService`      | `stateset.customer`        | 4    |
| `PaymentService`       | `stateset.payment`         | 2    |
| `ASNService`           | `stateset.asn`             | 10   |
| `PurchaseOrderService` | `stateset.purchase_order`  | 7    |
| `WarehouseService`     | `stateset.warehouse`       | 5    |
| `SupplierService`      | `stateset.supplier`        | 7    |
| `ReturnService`        | `stateset.return_order`    | 4    |
| `WarrantyService`      | `stateset.warranty`        | 4    |
| `ShipmentService`      | `stateset.shipment`        | 4    |
| `BOMService`           | `stateset.billofmaterials` | 7    |
| `PackagingService`     | `stateset.packaging`       | 1    |
| `PickingService`       | `stateset.picking`         | 1    |
| `TransferService`      | `stateset.transfer`        | 1    |
| `WorkOrderService`     | `stateset.work_order`      | 7    |

<Note>
  Note the package name for returns: `stateset.return_order`, not `stateset.return` — `return` is a
  reserved word in several target languages, so the package is qualified. Generated client namespaces
  follow suit.
</Note>

## A service in full

`ReturnService` is representative — a create, a get, a status transition, and a filtered list:

```protobuf theme={null}
syntax = "proto3";
package stateset.return_order;

import "google/protobuf/timestamp.proto";
import "common.proto";

message Return {
  string   id          = 1;
  string   order_id    = 2;
  string   customer_id = 3;
  repeated ReturnItem items = 4;
  string   status      = 5;
  string   reason      = 6;
  google.protobuf.Timestamp created_at = 7;
  google.protobuf.Timestamp updated_at = 8;
}

message ReturnItem {
  string product_id = 1;
  int32  quantity   = 2;
  string reason     = 3;
}

message ListReturnsRequest {
  string customer_id = 1;
  string order_id    = 2;
  string status      = 3;
  google.protobuf.Timestamp start_date = 4;
  google.protobuf.Timestamp end_date   = 5;
  common.PaginationRequest  pagination = 6;
}

message ListReturnsResponse {
  repeated Return returns = 1;
  common.PaginationResponse pagination = 2;
}

service ReturnService {
  rpc CreateReturn       (CreateReturnRequest)       returns (CreateReturnResponse);
  rpc GetReturn          (GetReturnRequest)          returns (GetReturnResponse);
  rpc UpdateReturnStatus (UpdateReturnStatusRequest) returns (UpdateReturnStatusResponse);
  rpc ListReturns        (ListReturnsRequest)        returns (ListReturnsResponse);
}
```

The filter fields on a `List` request are **AND-ed**, and an empty string means "don't filter on
this" rather than "match empty".

## Calling a service

```bash theme={null}
grpcurl -plaintext \
  -d '{"return_id": "ret_1042"}' \
  localhost:8081 stateset.return_order.ReturnService/GetReturn
```

```bash theme={null}
# List with pagination — note page is 1-based
grpcurl -plaintext \
  -d '{"status": "pending", "pagination": {"page": 1, "per_page": 25}}' \
  localhost:8081 stateset.return_order.ReturnService/ListReturns
```

## Errors

Failures come back as gRPC statuses rather than the REST error envelope. The mapping to expect:

| Status                | Means                                          | Retry?                      |
| --------------------- | ---------------------------------------------- | --------------------------- |
| `INVALID_ARGUMENT`    | Validation failure                             | No — deterministic          |
| `NOT_FOUND`           | No such record                                 | No                          |
| `FAILED_PRECONDITION` | The operation isn't valid in the current state | No — change the state first |
| `UNAVAILABLE`         | Upstream or transient failure                  | Yes, with backoff           |
| `DEADLINE_EXCEEDED`   | Timed out                                      | Yes, but see below          |
| `INTERNAL`            | Unexpected server-side failure                 | Once, then escalate         |

<Warning>
  A `DEADLINE_EXCEEDED` on a **write** does not tell you whether the write happened — the server may
  have committed and then failed to respond within the deadline. Treat writes as at-least-once and make
  them idempotent on your side, keyed on your own identifier.
</Warning>

## Related

* [Overview](/api-reference/overview) — the REST surface and its conventions
* [Sync Server gRPC flow](/stateset-sync-server-grpc-flow) — a production dispatch path over gRPC
* [Protocol Buffers](https://protobuf.dev/) — the IDL itself
