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

# gRPC API

> The REST send over HTTP/2 and protobuf, on a port of its own: when to choose it, how to connect, and how to get the contract — including straight from the gateway.

From **gateway 0.15.9**, FireFlo also takes messages over gRPC. It is the REST API's
[`POST /secure/send`](https://docs.fireflo.au/reference/api/send) with a binary transport: the same login, the same fields,
the same rating and charge, the same sender ID and template approval, the same routing check,
`client_ref` retry rule and per-account rate limit. **Once accepted, a message sent over gRPC is
indistinguishable from one sent over REST.**

It adds one thing REST does not have: a **receipt feed**. Ask for receipts without giving a webhook
and they wait for you in a durable queue you read over the same connection — no endpoint of your own
to run.

> [!NOTE]
>
> **gRPC is off unless your provider turns it on.** A gateway that has not been configured for it
> answers every call `UNAVAILABLE` with the error code `GRPC_DISABLED`. If you see that, the API exists
> but is not enabled on the platform you are calling — ask your provider for the gRPC address.

## When to choose it

| Choose gRPC when | Choose REST when |
| :- | :- |
| You send at high volume from a long-lived process | You send occasionally, or from a script |
| You want many calls in flight on one connection (HTTP/2) | Your platform only speaks HTTP/1.1 |
| You want to stream many messages without waiting for each answer | One request, one answer is all you need |
| You would rather pull receipts than run a webhook endpoint | You already run a receipt webhook |

A request is a few dozen bytes of protobuf instead of a JSON body, and
[`SendStream`](https://docs.fireflo.au/developers/grpc/sending#sendstream-many-messages-on-one-stream) sends many messages on
one stream without waiting for each answer. Neither changes what you are allowed to send or how fast:
**REST and gRPC share your account's messages-per-second limit**, so moving traffic from one to the
other does not buy more of it.

SMPP remains the third way in, and is separate again — see [Binding](https://docs.fireflo.au/developers/smpp/binding.md).

## Three services

| Service | Methods | What it does |
| :- | :- | :- |
| `fireflo.v1.AuthService` | `Login`, `Logout` | Exchange your login and password for a session token. See [Authentication and sessions](https://docs.fireflo.au/developers/grpc/authentication.md). |
| `fireflo.v1.SendService` | `Send`, `SendStream` | One message per call, or many on one stream. See [Sending messages](https://docs.fireflo.au/developers/grpc/sending.md). |
| `fireflo.v1.ReceiptService` | `Subscribe`, `Pull`, `Ack` | Collect the delivery receipts of your messages. See [Delivery receipts over gRPC](https://docs.fireflo.au/developers/grpc/receipts.md). |

## Connecting

Your provider gives you a **host and port**. On a gateway with nothing in front of it the port is
usually **8090**; behind a provider's TLS proxy it is often **443**.

| Transport | What it means for your client |
| :- | :- |
| **TLS** | The normal case on the public internet: the provider terminates TLS in front of the gateway, or the gateway speaks TLS itself. Use a secure channel — and with `grpcurl`, leave out `-plaintext`. |
| **Plain HTTP/2 (h2c)** | The gateway's own listener without TLS, for a private network or a test platform. Use an insecure channel — `grpcurl -plaintext`. |

gRPC needs HTTP/2 all the way. If calls fail at the transport level before the gateway answers,
something between you and it is speaking HTTP/1.1.

> [!TIP]
>
> **Keep your client's keepalive at 30 seconds or more.** The gateway accepts a client ping at most every
> 20 seconds; a client that pings more often is disconnected by the transport (`GOAWAY` with
> `too_many_pings`). Most libraries do not send keepalive pings at all unless told to, which is fine.

## The contract

**The contract is one file, `fireflo.proto`, protobuf package `fireflo.v1`.** It is reproduced in full
on [The proto file](https://docs.fireflo.au/reference/grpc/proto.md).

It is **frozen from 0.15.9** the way the REST API is frozen: field numbers are never reused or
renumbered, nothing is removed, and additions arrive as new optional fields, new messages and new
methods. A client generated from the 0.15.9 file keeps working against every later gateway; it simply
does not see what was added after it.

### Getting the proto

Any of these gives you the same file:

* **From the gateway itself.** Server reflection is on by default, so a tool that speaks it needs no
  file at all:

  ```bash theme={null}
  grpcurl -plaintext sms.example.com:8090 list
  grpcurl -plaintext sms.example.com:8090 describe fireflo.v1.SendRequest
  ```

  Your provider may have switched reflection off; then use one of the other two.
* **From this site**: [The proto file](https://docs.fireflo.au/reference/grpc/proto.md), to copy or download.
* **From your provider**, as `fireflo.proto`.

Generate a client with your language's usual tooling — `protoc` with the gRPC plugin, `buf generate`,
`python -m grpc_tools.protoc`, or the Gradle or Maven protobuf plugin. The file sets `go_package`
(`fireflo/v1;fireflov1`) and `csharp_namespace` (`FireFlo.V1`); in Java the generated classes are in
package `fireflo.v1`. It imports only `google/protobuf/timestamp.proto`, which every protobuf
distribution ships.

## Limits that apply to every call

| Limit | Default | What happens past it |
| :- | :- | :- |
| Messages per second | Set per account by your provider; unlimited unless they set one | `RESOURCE_EXHAUSTED`, `RATE_LIMITED`, retry after 1 second. **Shared with REST.** |
| Message size | 1 MiB per request, or per stream item | `RESOURCE_EXHAUSTED` from the transport, with no error detail |
| Requests in flight on one `SendStream` | 256 | The gateway stops reading the stream until you read results — see [SendStream](https://docs.fireflo.au/developers/grpc/sending.md#sendstream-many-messages-on-one-stream) |
| Session idle / lifetime | 1 hour / 24 hours | `UNAUTHENTICATED`, `SESSION_EXPIRED` — log in again |
| Sessions per login | 64 | A further `Login` ends that login's least recently used session |

Your provider can change each of these; the figures above are the defaults.

## Where to go next

> [card] [Authentication and sessions](https://docs.fireflo.au/developers/grpc/authentication.md)
>
> Log in once, carry the token, log in again on SESSION\_EXPIRED.

> [card] [Sending messages](https://docs.fireflo.au/developers/grpc/sending.md)
>
> Send and SendStream, every field beside its REST name.

> [card] [Errors and status codes](https://docs.fireflo.au/developers/grpc/errors.md)
>
> REST status, gRPC code, error code, and what to do.

> [card] [Delivery receipts over gRPC](https://docs.fireflo.au/developers/grpc/receipts.md)
>
> Subscribe, Pull and Ack — at least once.

> [card] [Examples](https://docs.fireflo.au/developers/grpc/examples.md)
>
> grpcurl, Python, Java and Go.

> [card] [The proto file](https://docs.fireflo.au/reference/grpc/proto.md)
>
> The whole contract.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.