Rust SDK
Install from crates.io and use typed services in your Rust backend with Tokio.
The official Rust SDK provides typed services, pagination, and webhook verification for server integrations with the public API. Keep the API key in your backend instead of distributing it in customer applications.
The SDK reference lists each resource's methods and parameters.
Install the SDK
Use Rust 1.90 or later and a Tokio runtime. The official
raims crate is available on crates.io.
From your application directory:
cargo add raims
cargo add tokio --features macros,rt-multi-threadCargo fetches from crates.io, selects the compatible stable version, and
records resolved versions in Cargo.lock. Keep the lockfile for repeatable
installation.
GitHub releases
continue to provide source code and the .crate archive. For a Git or local
path installation, read the
repository instructions.
Configure the client
Obtain a key through API keys and keep it in
RAIMS_API_KEY or your secret store. It determines company, environment,
and permissions. Sandbox and Production use https://api.raims.com.
use raims::RaimsClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = RaimsClient::new(std::env::var("RAIMS_API_KEY")?)?;
let balance = client.balances().retrieve().await?;
println!("HTTP status: {}", balance.last_response.status_code);
Ok(())
}Reuse the client; clones share its HTTP pool. Other snippets using await
belong inside asynchronous functions returning Result.
Use RaimsClient::builder with timeout, accepting std::time::Duration, and
max_read_retries to configure timeout and read retries. The timeout covers attempts and waits;
retries default to zero.
Create a customer and a charge
customer_tax_id, customer_key, and charge_key are application String
values. The first is a valid, authorized CPF or CNPJ; the keys are separate
and persisted before sending. due_date_unix is an i64 in UTC Unix seconds,
chosen and persisted for this charge.
use raims::{params::{CreateCustomerParams, CreateChargeParams}, Optional, RequestOptions};
let customer_params = CreateCustomerParams {
tax_id: Optional::Value(customer_tax_id),
..Default::default()
};
let customer_options = RequestOptions {
idempotency_key: Some(customer_key),
..Default::default()
};
let customer = client.customers()
.create_with_options(&customer_params, &customer_options).await?;
let charge_params = CreateChargeParams {
customer_id: Optional::Value(customer.data.id),
amount_cents: Optional::Value(15000),
due_date: Optional::Value(due_date_unix),
title: Optional::Value("Order 1234".to_owned()),
..Default::default()
};
let charge_options = RequestOptions {
idempotency_key: Some(charge_key),
..Default::default()
};
let charge = client.charges()
.create_with_options(&charge_params, &charge_options).await?;
let pending = charge.last_response.status_code == 202;15000 represents BRL 150.00. Optional::Unset leaves a field absent,
Optional::Null sends null where permitted, and Optional::Value(...) sets
a value. For updates, omission preserves a field and null may clear it under
the contract. ApiResponse<T> contains data, last_response, and raw;
use raw when response absence and null must be distinguished.
Pagination and pending results
use raims::{params::ListCustomersParams, Optional};
let filters = ListCustomersParams {
page_size: Optional::Value(50),
..Default::default()
};
let mut pages = client.customers().list_pages(&filters)?;
while let Some(response) = pages.next_page().await? {
for customer in response.data.list {
process_customer(customer);
}
}process_customer represents your application. Creating a pager sends no
HTTP; next_page().await fetches the first page and follows its cursors.
Reading a response list does not fetch pages itself. The pager preserves
filters and options; a failed fetch does not advance its cursor. Use
previous_page().await to move backward. Cursors are opaque; do not combine
after and before.
HTTP 202 remains pending. Retrieve the resource or follow its appropriate
webhook before confirming payment, refund, or cancellation.
Idempotency and errors
match client.customers().retrieve(&customer_id).await {
Ok(response) => process_customer(response.data),
Err(error) => handle_failure(
error.kind(), error.status_code(), error.code(), error.request_id()
),
}The handlers belong to your application. Requests return
Result<ApiResponse<T>, Error>; kind(), status_code(), code(), and
request_id() help decide the next action. Do not treat human messages as
codes or log complete bodies or secrets.
The SDK does not generate keys or retry writes automatically. After a lost
response, reconcile the operation and preserve the original key and
parameters if the endpoint permits another attempt. max_read_retries
enables eligible read retries only. Retry-After and attempts share the
timeout budget; local cancellation does not reverse work accepted by the API.
See Idempotency.
Use Sandbox
Use a Sandbox credential and a charge from that environment:
let sandbox = RaimsClient::new(std::env::var("RAIMS_SANDBOX_API_KEY")?)?;
let result = sandbox.simulations().charges()
.confirm_payment(&sandbox_charge_id).await?;sandbox_charge_id is a String obtained in your Sandbox integration. The
SDK does not select an environment by header or convert a Production
credential. See Simulations. Email requests
and webhooks may still reach external destinations; use authorized ones only.
Receive webhooks
Preserve raw_body as &[u8], signing_headers as a list of (&str, &str)
pairs, and webhook_secret as the webhook's secret_key string. Include all
occurrences of webhook-id, webhook-timestamp, and webhook-signature;
do not collapse them before verification.
use std::time::SystemTime;
use raims::{construct_webhook_event, DEFAULT_WEBHOOK_TOLERANCE};
let event = construct_webhook_event(
raw_body,
&signing_headers,
&webhook_secret,
DEFAULT_WEBHOOK_TOLERANCE,
SystemTime::now(),
)?;
persist_event(event);persist_event belongs to your application. The signature is checked before
JSON decoding; do not reserialize the body. The default tolerance is five
minutes in either direction; keep the server clock synchronized.
verify_webhook_signature authenticates without decoding the event.
Check type and environment, deduplicate the event id, and persist the work
before returning success. webhook-id identifies the delivery and does not
replace the event ID. See Receive events.
Update the SDK
Read the release notes
and update the SDK within the requirement declared in Cargo.toml:
cargo update -p raimsThis command preserves the existing requirement. To select the current
stable version outside that requirement or migrate from Git or a local
directory, record the dependency options your application uses. Remove only
the raims entry from the manifest that declares it and keep Cargo.lock.
For an inherited workspace dependency, change its [workspace.dependencies]
entry.
If it is optional, preserve and temporarily remove dependency references in
[features], such as dep:raims, to keep the manifest valid. After adding
the dependency, restore those declarations together with its optional and
feature options. From your application directory:
cargo add raimsReapply the dependency options, such as features, and review the entry in
Cargo.toml: it must use the registry version requirement selected by Cargo,
without git, path, branch, tag, or rev.
Review and keep the updated Cargo.lock, and test the flows used by your
integration before updating the application. Installation does not apply
future updates automatically.