Skip to content

New Truto SDKs for Go, Java, and Rust

Truto now has official SDKs for Go, Java, and Rust, alongside the TypeScript and Python SDKs. Each one covers the Unified, Proxy, Custom, and MCP APIs and most of the Admin API, with typed models, retries, and cursor pagination built in.

Sidharth Verma Sidharth Verma · · 5 min read
New Truto SDKs for Go, Java, and Rust

Truto has had two server-side SDKs for a while: TypeScript and Python. If your backend was written in anything else, you called the REST API directly and wrote your own pagination loop, retry logic, and response types.

Today we're adding three more: Go, Java, and Rust.

Language Package Install Docs
TypeScript @truto/truto-ts-sdk npm install @truto/truto-ts-sdk TypeScript SDK
Python truto-python-sdk pip install truto-python-sdk Python SDK
Go github.com/trutohq/truto-go-sdk go get github.com/trutohq/truto-go-sdk@latest Go SDK
Java one.truto:truto-java-sdk Maven or Gradle, version 0.1.0 Java SDK
Rust truto cargo add truto Rust SDK

All five talk to the same API. You can run a Python service and a Go service against the same Truto environment, and they see the same tenants, integrated accounts, and sync jobs.

What the new SDKs cover

Each SDK covers the Unified, Proxy, Custom, and MCP APIs and most of the Admin API:

  • Unified API. List, get, create, update, delete, and custom methods on any unified model, plus the meta endpoints that tell you what an integration supports.
  • Proxy API and Custom API. Call an integration's own endpoints through Truto, with Truto handling auth. Custom API calls can return raw bytes for file downloads.
  • MCP. Initialize, list tools, and call tools on an integrated account's MCP server.
  • Admin API. Integrated accounts, integrations, tenants, link tokens, session tokens, unified models and mappings, sync jobs and their runs, cron triggers and templates, webhooks, workflows, datastores, static gates, observability destinations, analytics, and logs.

No SDK covers notification destinations, SSO, SCIM, or group mappings yet, and the Go SDK has no alarms yet. For an endpoint an SDK doesn't wrap, the Go and Java SDKs have a raw request method (client.Do in Go, truto.http() in Java). It sends any request with the same auth, retries, and error handling. The Rust SDK doesn't have a raw request method yet.

The same call in three languages

Here is one task in each language: list every CRM contact for an integrated account through the Unified API. The SDK follows next_cursor for you.

Go

client := truto.NewClient(os.Getenv("TRUTO_API_TOKEN"))
 
contacts := client.Unified.List(ctx, truto.UnifiedResource{
	Model:               "crm",
	Resource:            "contacts",
	IntegratedAccountID: accountID,
})
for contact, err := range contacts.Seq() {
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(contact["first_name"])
}

Java

TrutoClient truto = TrutoClient.builder()
    .token(System.getenv("TRUTO_API_TOKEN"))
    .build();
 
for (TrutoRecord contact : truto.unifiedApi().list("crm", "contacts", accountId)) {
    System.out.println(contact.getString("first_name"));
}

Rust

let client = truto::Client::new(std::env::var("TRUTO_API_TOKEN").unwrap());
 
let contacts = client
    .unified_api()
    .list("crm", "contacts", &account_id)
    .collect_all()
    .await?;
for contact in &contacts {
    println!("{:?}", contact.get("first_name"));
}

Each SDK's API follows its own language. Go takes a context.Context first and returns an iterator you can range over. Java returns a lazy Pager that works in a for loop and as a Stream, with CompletableFuture variants for async code. Rust returns request builders you .await, and pagers that turn into a Stream.

Typed models from the OpenAPI spec

Admin API responses and request bodies are typed. The types are generated from the same OpenAPI spec that powers the API reference, so a field in the docs is a field in your editor's autocomplete.

The generated types are lenient, because Truto adds fields and enum values over time:

  • Unknown fields are ignored, so a new API field doesn't break an older SDK.
  • Enums are open. A status the SDK doesn't know yet still decodes, and you can read its raw value.
  • Unions keep the raw JSON and decode on demand, so you only pay for the shape you ask for.

Unified, Proxy, and Custom API responses depend on the integration behind them, so they come back as a generic record. When you know the shape you want, decode it into your own type:

#[derive(serde::Deserialize)]
struct Contact {
    id: String,
    first_name: Option<String>,
}
 
let contacts: Vec<Contact> = client
    .unified_api()
    .list("crm", "contacts", &account_id)
    .typed::<Contact>()
    .collect_all()
    .await?;

Go has truto.Decode[Contact](record), and Java takes a Contact.class argument on get and list.

Retries, rate limits, and errors

Truto enforces rate limits per API token and per integrated account, and the third-party APIs behind it fail in their own ways. The new SDKs handle the common cases by default:

  • They retry 408, 409, 425, 429, 502, 503, and 504 responses and connection errors, up to 3 times.
  • A 429 waits for the Retry-After header, or 10 seconds when the header is missing.
  • Other retryable statuses back off exponentially with jitter, from 500 ms up to 10 seconds.
  • Each attempt times out after 30 seconds. Timeouts are not retried.

All of these can be changed for the whole client or for a single call. For example, turn retries off for a write that isn't safe to send twice:

RequestOptions once = RequestOptions.builder().noRetry().build();
truto.unifiedApi().create("crm", "contacts", accountId, contact, null, once);

When a request fails, the error carries the HTTP status, the parsed JSON body, and the response headers. Truto's error message and truto_error_insight are there without any extra parsing, along with helpers such as IsNotFound and isRateLimited.

Where the TypeScript and Python SDKs fit

Nothing changes for the TypeScript and Python SDKs. They're still the quickest path on Node.js and in async Python, and the TypeScript SDK has a request queue and FormData uploads that the new SDKs don't have yet.

On the frontend, keep using the Link SDK to show the connection flow to your users. It pairs with any of the five backend SDKs: your backend creates a link token, and the Link SDK uses it to connect an account.

Get started

  1. Create an API token in the Truto dashboard.
  2. Install the SDK for your language from the table above.
  3. Follow the guide for your language: Go, Java, or Rust. Each one has a quick start and a reference for every method.

All three SDKs are MIT-licensed and open source: truto-go-sdk, truto-java-sdk, and truto-rust-sdk. Issues and pull requests are welcome.

If you need an SDK for another language, email support@truto.one.

FAQ

Which languages does Truto have SDKs for?
TypeScript (@truto/truto-ts-sdk on npm), Python (truto-python-sdk on PyPI), Go (github.com/trutohq/truto-go-sdk), Java (one.truto:truto-java-sdk on Maven Central), and Rust (the truto crate on crates.io). For the browser there is also the Link SDK (@truto/truto-link-sdk), which embeds the connection flow in your frontend.
Do the Go, Java, and Rust SDKs cover the same APIs as the TypeScript and Python SDKs?
They cover the same core API: the Unified API, Proxy API, Custom API, MCP, and most of the Admin API (integrated accounts, integrations, tenants, link and session tokens, sync jobs, webhooks, workflows, datastores, analytics, and logs). None of the SDKs cover notification destinations, SSO, SCIM, or group mappings yet, and the Go SDK has no alarms yet. The Go and Java SDKs have a raw request method for endpoints they don't wrap, with the same auth and retries. The Rust SDK doesn't have one yet.
Do the new SDKs retry rate-limited requests?
Yes. They retry 408, 409, 425, 429, 502, 503, and 504 responses and connection errors, up to 3 times by default. A 429 waits for the Retry-After header (10 seconds when it's missing), and other statuses back off exponentially with jitter. Timeouts, retries, and extra retry statuses can be changed for the whole client or for one request.
Are the response types generated or hand-written?
Admin API types are generated from Truto's OpenAPI spec, so they match the API reference. Unified, Proxy, and Custom API responses depend on the integration, so they come back as a generic record (a map) that you can decode into your own type.
What versions of Go, Java, and Rust do the SDKs need?
Go 1.23 or later, Java 11 or later, and Rust 1.88 or later with a tokio runtime. The Go SDK uses only the standard library, and the Java SDK's only runtime dependency is Jackson.

More from our Blog