alguna
Rust SDK for the Alguna API: usage-based billing, subscriptions, invoicing and payments.
Install
The crate uses rustls for TLS. It needs an async runtime such as tokio.
Client
Create an API key in the dashboard under Settings → Connections → Developers → API
keys. A key looks like <key_id>.<key_secret>. The key is a secret, so use the SDK on
a server only.
use *;
use ApiClientBuilder;
If there is no key, build() and Alguna::new return ApiError::Configuration and send
nothing.
| Setting | Builder method | Default |
|---|---|---|
| API key | api_key |
the ALGUNA_API_KEY environment variable |
| API version | api_version |
2026-04-01, the version this release targets |
| Base URL | new(url) |
https://api.alguna.io |
| Timeout | timeout |
60 seconds for each attempt |
| Retries | max_retries |
2 |
| HTTP client | reqwest_client |
one built from the timeout and user agent |
The SDK sends the key as Authorization: Bearer <key>. Every request carries an
Alguna-Version header, so the response types match the API. For the sandbox, use
ApiClientBuilder::new("https://api.sandbox.alguna.io").
Requests
Each resource is a field of the client: client.customers, client.invoices and so
on. A method takes its request and an optional RequestOptions, which overrides the
client settings for that call. Every list filter is optional.
use *;
async
Pagination
list returns one page. list_paginated returns a Stream of every item. It loads the
next page when the stream needs it, from offset (default 0). Add futures = "0.3" for
StreamExt.
use *;
use StreamExt;
async
Idempotency and retries
Every request other than a GET carries an Idempotency-Key header. The SDK makes a
UUID v4 key for each call and sends the same key on every retry of that call, so the
API acts once. To make a call safe to repeat later, for example after your process
stops, set your own key:
use *;
async
client.events.ingest, client.credits.check and client.credits.track are different.
The API identifies their work by the request body, so the SDK makes no key for them and
still retries them. The API removes duplicate events by unique_id, and
credits.track draws credit once for the same unique_ids. A key replaces that
identity on credits.track, so a new key on each call would make a redelivered batch
draw credit twice. A key that you set is sent on every attempt. credits.check with
reserve needs your key, because the key identifies the hold.
By default the SDK retries a call 2 times after:
- a network error: the connection is refused, reset or closed before the response, or the attempt times out;
- a 408, 429, 502, 503 or 504 response;
- a 409 response with
Retry-After. The API sends it while a request with the same idempotency key is still running. Any other 409 is a conflict, and the SDK does not retry it.
A retry waits 1 second, then 2 seconds, and so on, each ±10%. If the response has
Retry-After (seconds or an HTTP date), the retry waits that long, up to 60 seconds.
Set max_retries on the builder or on RequestOptions. 0 turns retries off.
To stop a call, drop its future, for example with tokio::time::timeout. A dropped
call makes no more attempts.
Timeouts
timeout on the builder limits each attempt. The default is 60 seconds.
timeout_seconds on RequestOptions replaces it for one call. A custom
reqwest_client keeps its own timeout.
use *;
use ApiClientBuilder;
use Duration;
async
Errors
Every call returns Result<_, ApiError>. The enum is #[non_exhaustive], so keep a
wildcard arm. An error prints the API's reason: the body's detail, else its title,
else its message, else the HTTP status text. For example:
NotFoundError: Resource not found - customer cus_1 not found.
use *;
async
A network failure is ApiError::Network. Its cause is the error's source().
Webhooks
Alguna sends webhooks through Svix. Verify the signature before you trust a payload:
give the raw request body and its svix-id, svix-timestamp and svix-signature
headers to the svix crate
(Webhook::new(secret)?.verify(body, &headers)?). Then read the event. Each event
type has a payload type in this crate, such as WebhookPaymentCreatedPayload for
payment.created. The example also needs serde_json.
use *;
// `body` is the raw request body, after its signature is verified.
Reference
Every endpoint and type is in reference.md. The API documentation is at alguna.com/docs.
About this repo
Alguna generates this crate from the Alguna API spec in a private repository. Open issues here. Alguna ports code changes to that repository, so a pull request here is not merged as it is.