SendService has two methods. Send takes one message and gives one answer, and mirrors
POST /secure/send field for field. SendStream carries many messages on
one bidirectional stream, for sustained volume.
Both need the session token from Login in the authorization
metadata.
Send: one message
Fields
Every field exceptto is optional: a field you do not set behaves exactly as a JSON key you leave
out of a REST request, and takes the same default. The same approvals, products, TLV grammar and
limits apply, because both reach the same checks.
REST’s
dlr_method and tags are not carried; their field numbers are reserved so they can never be
reused for something else.
custom_tlvs values
Each value is a TlvValue holding exactly one of:
The key decides the wire encoding, exactly as on REST.
"0x1401:Int8" with int_value: 42 is
the 8-byte integer 42, as "0x1401:Int8": 42 is on REST.
grpcurl reads — a 64-bit integer is written as a string. Generated clients take
a native integer.
Receipts: dlr and dlr_url
The webhook always wins: a message with a
dlr_url never appears on the feed.
If your provider has switched the receipt feed off,
dlr: true without a dlr_url is refused
INVALID_ARGUMENT naming dlr_url — the same refusal REST gives — because the receipts would have
nowhere to go.The answer
price is a string on purpose: a decimal amount survives every language unchanged that way, where a
floating-point number would not.
Retrying safely with client_ref
Set client_ref on every send you might retry. A repeat inside 24 hours from the same account —
over gRPC or REST, whichever login sent it — is answered with the first send’s message_id and
duplicate: true, and nothing is sent or charged again.
A send that was refused frees its reference, so the corrected request may reuse it. The rules
are REST’s, described in full under
Retrying safely with client_ref — including
the one narrow gap on a gateway cluster.
This matters most for one answer in particular: UNKNOWN with OUTCOME_UNKNOWN, where the message may
be on its way. Retry that only with the same client_ref. See
Errors and status codes.
SendStream: many messages on one stream
For sustained high volume. You write SendStreamRequests and read SendStreamResults on one
bidirectional stream.
Each request is a correlation_id of your choosing and a SendRequest — exactly the message you
would pass to Send.
Each result is:
correlation_id must be 1–64 characters. An empty or longer one is answered — for that request only —
INVALID_ARGUMENT with field: correlation_id. Use something unique per request on the stream; your
client_ref is often the natural choice.
One result per request, in any order
Requests are submitted concurrently, so a quick one overtakes a slow one. Match oncorrelation_id, never on position.
A refusal is a result, not a stream error
An empty balance, the rate limit or a bad field answers that one request, and the stream carries on. The stream itself ends only when you close your side — then withOK, after the last result — or
when the gateway stops.
Read continuously, or the stream stalls
The gateway holds at most 256 of your requests at once on one stream — being submitted, or answered and waiting for you to read the result. Past that it stops reading from the stream until a result has been read, and ordinary HTTP/2 flow control holds your writes back. So: write as fast as your library lets you, and read results continuously on another thread or task. A client that writes everything first and reads afterwards stops after 256. For more concurrency, open more streams — each has its own 256. They all share your account’s messages-per-second limit, so more streams buy concurrency, not rate.When the gateway stops
A gateway being restarted ends its streams cleanly:- Requests already being submitted finish, and their results are sent.
- Requests received but not yet started are answered
UNAVAILABLE/SHUTTING_DOWNwithout being submitted. - The stream ends with
UNAVAILABLE(SHUTTING_DOWN).
client_ref, so nothing is sent twice.
A connection that drops without that orderly end leaves you with requests that have no result. Resend
those too, with the same client_ref: whichever were accepted come back duplicate: true.
Related
Examples
Send and SendStream in Python, Java and Go.
POST /secure/send
The REST twin of every field above.