> ## 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.

# The proto file

> fireflo.proto, package fireflo.v1: the whole gRPC contract, frozen from gateway 0.15.9, to copy or download.

The complete gRPC contract. Generate your client from this file — see
[Getting the proto](https://docs.fireflo.au/developers/grpc/overview.md#getting-the-proto) for the other ways to obtain it,
including straight from the gateway by server reflection.

> [card] [Download fireflo.proto](https://docs.fireflo.au/files/fireflo.proto)
>
> The same file as below, ready for `protoc`, `buf` or your build plugin.

## The rules it follows

* **Frozen from 0.15.9.** Field numbers are never reused or renumbered and nothing is removed.
  Additions arrive as new optional fields, new messages and new methods, so a client generated from
  this file keeps working against every later gateway.
* **Leave out what you do not need.** Every `SendRequest` field except `to` is `optional`, and a field
  you do not set takes the default REST gives an absent JSON key.
* **One import**, `google/protobuf/timestamp.proto`, which every protobuf distribution ships.
* **Language options**: `go_package` is `fireflo/v1;fireflov1`, `csharp_namespace` is `FireFlo.V1`, and
  Java classes are generated into package `fireflo.v1` as separate files.

Gateway 0.15.10 added `AuthService.PlatformLogin`, `PlatformLoginRequest` and `SendRequest.account`
(field 17) for platforms that provision accounts with the management token; a client generated from
the 0.15.9 file keeps working unchanged.

Fields 15 and 16 of `SendRequest` are reserved for REST's `dlr_method` and `tags`, which are not
carried over gRPC.

## `fireflo.proto`

```protobuf fireflo.proto theme={null}
// FireFlo SMS gateway: gRPC API, version 1.
// Frozen contract. Field numbers are never reused or renumbered; additions only.
syntax = "proto3";

package fireflo.v1;

option java_multiple_files = true;
option java_outer_classname = "FireFloProto";
option go_package = "fireflo/v1;fireflov1";
option csharp_namespace = "FireFlo.V1";

import "google/protobuf/timestamp.proto";

// ---------------------------------------------------------------- Auth
// Call Login once per channel; send the token on every other call as
//   authorization: Bearer <session_token>
service AuthService {
  rpc Login(LoginRequest) returns (LoginResponse);
  rpc Logout(LogoutRequest) returns (LogoutResponse);
  // A platform session (from 0.15.10): for a platform that provisions accounts with
  // the gateway's management token and sends on their behalf. No password; the call
  // is signed with the management token instead (see PlatformLoginRequest). The
  // token returned is used exactly as a Login token.
  rpc PlatformLogin(PlatformLoginRequest) returns (LoginResponse);
}

message LoginRequest {
  string system_id = 1;   // the HTTP login (same as REST Basic username)
  string password  = 2;
}
message LoginResponse {
  string session_token = 1;
  google.protobuf.Timestamp expires_at = 2;   // absolute cap; idle expiry also applies
  int64  idle_timeout_seconds = 3;
}
message LogoutRequest {}
message LogoutResponse {}

// Signed, not passworded. The call carries three metadata entries:
//   x-fireflo-timestamp  Unix time in seconds, within 60 s of the gateway's clock
//   x-fireflo-nonce      1..128 characters, unique per call; a nonce is accepted once
//   x-fireflo-signature  hex HMAC-SHA256, keyed by the management token, of these
//                        five lines joined by "\n", with no trailing newline:
//                          POST
//                          /fireflo.v1.AuthService/PlatformLogin
//                          <the timestamp, as sent>
//                          <the nonce, as sent>
//                          <lowercase hex SHA-256 of this message's serialized bytes>
// The session acts for the accounts whose ref (the marker the platform provisioned
// them with) starts with this ref, and for no other.
message PlatformLoginRequest {
  optional string ref = 1;   // required: a prefix of the accounts' refs, ending in "/"
}

// ---------------------------------------------------------------- Send
service SendService {
  // One message. Mirrors POST /secure/send.
  rpc Send(SendRequest) returns (SendResponse);
  // Many messages on one stream. Results arrive in any order, one per request,
  // matched by correlation_id. A refusal is a result, not a stream error.
  rpc SendStream(stream SendStreamRequest) returns (stream SendStreamResult);
}

// Field for field the body of POST /secure/send. Unset optional fields take the
// same defaults as an absent JSON key.
message SendRequest {
  string to = 1;
  optional string from = 2;
  // exactly one of content / hex_content
  optional string content = 3;
  optional string hex_content = 4;
  optional int32  coding = 5;            // 0 GSM-7 default, 8 UCS-2, ... as REST
  optional int32  priority = 6;          // 0..3
  optional int32  validity_period = 7;   // minutes
  optional string sdt = 8;               // scheduled delivery time, REST format
  optional bool   dlr = 9;               // request receipts (to the feed unless dlr_url set)
  optional int32  dlr_level = 10;        // 1 progress, 2 final, 3 both
  map<string, TlvValue> custom_tlvs = 11; // key "0xTAG" or "0xTAG:Type", as REST
  optional string client_ref = 12;       // 1..64 printable chars; idempotency key
  optional string product = 13;
  optional string dlr_url = 14;          // if set, receipts go to this webhook and NOT the feed
  reserved 15, 16;                       // dlr_method, tags (REST/Jasmin compatibility; not carried)
  // Platform sessions only, and required on them: the account to send as. The
  // message runs under that account's enabled HTTP login, with its prices, limits
  // and receipt feed. Refused on a Login session.
  optional string account = 17;
}

message TlvValue {
  oneof value {
    string string_value = 1;
    int64  int_value    = 2;
    uint64 uint_value   = 3;   // up to 2^64-1 exactly, the same range REST takes as a JSON integer
  }
}

message SendResponse {
  string message_id = 1;
  bool   duplicate = 2;        // client_ref seen before: message_id is the original's, nothing charged
  optional string price = 3;   // decimal string, 4 places, whole message (REST "price")
  optional string currency = 4;
  optional int32  segments = 5;
  bool   unrated = 6;
}

message SendStreamRequest {
  string correlation_id = 1;   // client-chosen, 1..64 chars, echoed back
  SendRequest request = 2;
}

message SendStreamResult {
  string correlation_id = 1;
  int32  code = 2;             // google.rpc.Code value the unary Send would have returned (0 = OK)
  SendResponse response = 3;   // set when code == 0
  ErrorDetail error = 4;       // set when code != 0
}

// Packed into google.rpc.Status.details on every non-OK unary status,
// and inline in SendStreamResult.
message ErrorDetail {
  int32  http_status = 1;      // what POST /secure/send would have answered
  string code = 2;             // REST error code, e.g. RATE_LIMITED, OUTCOME_UNKNOWN, SHUTTING_DOWN
  string message = 3;          // REST error message, verbatim
  optional int32  retry_after_seconds = 4;
  optional string message_id = 5;   // OUTCOME_UNKNOWN only
  optional string field = 6;        // the offending request field for INVALID_ARGUMENT
}

// ---------------------------------------------------------------- Receipts
// One durable queue per HTTP login. Subscribe and Pull draw from the same queue.
// Delivery is at least once: a receipt is removed only by Ack. An unacked receipt
// is redelivered after its lease (default 120 s) or as soon as its stream closes.
// On a platform session the three calls read the receipts of every account the
// platform owns; account_id and system_id say whose each one is. An ack token is
// accepted only by the kind of session (login or platform) it was delivered to.
service ReceiptService {
  rpc Subscribe(SubscribeRequest) returns (stream Receipt);
  rpc Pull(PullRequest) returns (PullResponse);
  rpc Ack(AckRequest) returns (AckResponse);
}

message SubscribeRequest {
  optional int32 window = 1;   // max unacked receipts in flight on this stream; server caps
}
message PullRequest {
  int32 max = 1;               // 1..1000 (server cap)
  optional int32 wait_seconds = 2;   // long-poll up to 20 s when empty; 0 = return at once
}
message PullResponse {
  repeated Receipt receipts = 1;
}
message AckRequest {
  repeated string ack_tokens = 1;    // up to 1000
}
message AckResponse {
  int32 acked = 1;                   // removed now
  int32 already_gone = 2;            // unknown, already acked or expired: not an error
}

// The receipt webhook JSON (docs.fireflo.au/reference/api/dlr-webhook), one field per key, plus delivery fields.
message Receipt {
  string id = 1;                     // message_id from SendResponse
  string stat = 2;                   // DELIVRD, UNDELIV, EXPIRED, REJECTD, UNKNOWN, ACCEPTD, ENROUTE...
  int32  level = 3;                  // 1 progress, 2 final
  optional string sub_date = 4;
  optional string done_date = 5;
  optional string to = 6;
  optional string from = 7;
  optional string operator_msg_id = 8;
  optional string account_id = 9;
  optional string system_id = 10;
  optional int32  parts = 11;
  optional string vendor = 12;       // absent unless the operator shares it
  optional string err = 13;
  string ack_token = 14;
  int32  delivery_count = 15;        // 1 on first delivery; >1 means a redelivery
}
```

## Where each part is explained

| Part | Page |
| :- | :- |
| `AuthService`, `LoginResponse`, `PlatformLoginRequest` | [Authentication and sessions](https://docs.fireflo.au/developers/grpc/authentication.md) |
| `SendService`, `SendRequest`, `TlvValue`, `SendResponse`, `SendStreamRequest`, `SendStreamResult` | [Sending messages](https://docs.fireflo.au/developers/grpc/sending.md) |
| `ErrorDetail` | [Errors and status codes](https://docs.fireflo.au/developers/grpc/errors.md) |
| `ReceiptService`, `Receipt`, `PullRequest`, `SubscribeRequest`, `AckRequest`, `AckResponse` | [Delivery receipts over gRPC](https://docs.fireflo.au/developers/grpc/receipts.md) |


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