> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aireserve.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK quickstart

> Install an official AI Reserve SDK and make your first request — a complete round trip in five languages.

## Packages & installation

| Language        | Package                                                | Requires         | Runtime dependencies                            |
| --------------- | ------------------------------------------------------ | ---------------- | ----------------------------------------------- |
| Python          | `audacity-sdk` (PyPI)                                  | Python 3.9+      | None — stdlib only                              |
| TypeScript / JS | `@audacity/sdk` (npm)                                  | Node ≥ 18 or Bun | None — global fetch, dual ESM/CJS, full `.d.ts` |
| Go              | `github.com/Audacity-Investments/audacity-sdk-go`      | Go 1.22+         | None — stdlib only                              |
| Java            | `com.audacityinvestments:audacity-sdk` (Maven Central) | Java 11+         | Gson only — uses `java.net.http`                |
| Rust            | `audacity-sdk` (crates.io)                             | Rust (tokio)     | `reqwest`, `serde`, `tokio`                     |

<CodeGroup>
  ```bash Python theme={"dark"}
  pip install audacity-sdk
  ```

  ```bash TypeScript theme={"dark"}
  npm install @audacity/sdk
  # or
  bun add @audacity/sdk
  ```

  ```bash Go theme={"dark"}
  go get github.com/Audacity-Investments/audacity-sdk-go
  ```

  ```xml Java theme={"dark"}
  <dependency>
    <groupId>com.audacityinvestments</groupId>
    <artifactId>audacity-sdk</artifactId>
    <version>0.4.0</version>
  </dependency>
  ```

  ```toml Rust theme={"dark"}
  [dependencies]
  audacity-sdk = "0.4.0"
  tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
  ```
</CodeGroup>

<Note>
  The Python distribution is named `audacity-sdk`, but the import stays
  `audacity` — exactly the boto3 pattern of installing one name and importing another.
</Note>

## Your first request

A complete request/response round trip with the official AI Reserve SDKs. Set
`AUDACITY_API_KEY` in your environment, pick a model, and run — the shapes below
will look familiar to anyone who has used Bedrock's `Converse`. (Using the OpenAI
or Anthropic SDK instead? See [connect what you already use](/connect).)

<CodeGroup>
  ```python Python theme={"dark"}
  from audacity import Audacity

  client = Audacity(api_key="aireserve_api_…")   # or set AUDACITY_API_KEY

  response = client.converse(
      modelId="gpt-5.4-mini",
      messages=[{"role": "user", "content": [{"text": "What is 2+2?"}]}],
      inferenceConfig={"maxTokens": 256, "temperature": 0.0},
  )

  print(response["output"]["message"]["content"][0]["text"])
  print(response["stopReason"])   # "end_turn"
  print(response["usage"])        # {"inputTokens": …, "outputTokens": …, "totalTokens": …}
  print(response["metrics"])      # {"latencyMs": …}
  ```

  ```typescript TypeScript theme={"dark"}
  import { AudacityRuntimeClient, ConverseCommand } from "@audacity/sdk";

  const client = new AudacityRuntimeClient({ apiKey: process.env.AUDACITY_API_KEY });

  const response = await client.send(
    new ConverseCommand({
      modelId: "gpt-5.4-mini",
      messages: [{ role: "user", content: [{ text: "Hello!" }] }],
      inferenceConfig: { maxTokens: 500, temperature: 0.2 },
    })
  );

  console.log(response.output?.message?.content?.[0]?.text);
  // response.stopReason, response.usage, response.metrics.latencyMs also populated
  ```

  ```go Go theme={"dark"}
  package main

  import (
      "context"
      "fmt"
      "log"

      "github.com/Audacity-Investments/audacity-sdk-go"
      "github.com/Audacity-Investments/audacity-sdk-go/audacityruntime"
      "github.com/Audacity-Investments/audacity-sdk-go/audacityruntime/types"
  )

  func main() {
      // Reads AUDACITY_API_KEY from the environment.
      client := audacityruntime.New(audacityruntime.Options{})

      resp, err := client.Converse(context.Background(), &audacityruntime.ConverseInput{
          ModelId: audacity.String("gpt-5.4-mini"),
          Messages: []types.Message{{
              Role:    types.ConversationRoleUser,
              Content: []types.ContentBlock{
                  &types.ContentBlockMemberText{Value: "Hello, world!"},
              },
          }},
          InferenceConfig: &types.InferenceConfiguration{
              MaxTokens:   audacity.Int32(500),
              Temperature: audacity.Float32(0.2),
          },
      })
      if err != nil {
          log.Fatal(err)
      }

      out := resp.Output.(*types.ConverseOutputMemberMessage)
      text := out.Value.Content[0].(*types.ContentBlockMemberText).Value
      fmt.Println(text)
  }
  ```

  ```java Java theme={"dark"}
  import com.audacity.sdk.*;

  var client = AudacityRuntimeClient.builder()
      .apiKey(System.getenv("AUDACITY_API_KEY"))
      .build();

  ConverseResponse response = client.converse(request -> request
      .modelId("gpt-5.4-mini")
      .messages(Message.builder()
          .role(ConversationRole.USER)
          .content(ContentBlock.fromText("What is 2 + 2?"))
          .build())
      .inferenceConfig(cfg -> cfg.maxTokens(500).temperature(0.2f)));

  System.out.println(response.output().message().content().get(0).text());
  System.out.printf("Stop reason : %s%n", response.stopReason());
  System.out.printf("Input tokens: %d%n", response.usage().inputTokens());
  System.out.printf("Latency ms  : %d%n", response.metrics().latencyMs());
  ```

  ```rust Rust theme={"dark"}
  use audacity_sdk::{Client, ContentBlock, ConversationRole, Message};

  #[tokio::main]
  async fn main() -> Result<(), audacity_sdk::Error> {
      // Reads AUDACITY_API_KEY from the environment.
      let client = Client::from_env()?;

      let response = client.converse()
          .model_id("gpt-5.4-mini")
          .messages(
              Message::builder()
                  .role(ConversationRole::User)
                  .content(ContentBlock::Text("Hello!".into()))
                  .build()?
          )
          .inference_config(
              audacity_sdk::InferenceConfiguration::builder()
                  .max_tokens(500)
                  .temperature(0.2)
                  .build()
          )
          .send()
          .await?;

      let text = response
          .output().unwrap()
          .as_message().unwrap()
          .content().first().unwrap()
          .as_text().unwrap();

      println!("{text}");
      Ok(())
  }
  ```
</CodeGroup>

## If your first request fails

The fastest diagnosis: open the portal, find your key under
**Profile → API Keys**, and click **Test** — it fires one real
request through the gateway with that key and translates any failure into the fix.
The same translations, keyed to what the error response says:

| What the error says                                 | What it means                                                        | Fix                                                                                |
| --------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| 401/403 — `invalid_api_key`, `AUTHENTICATION_ERROR` | This key can't sign in — it was revoked or its owner was deactivated | Create a new key in the portal and update your app to use it                       |
| 403 — `MODEL_NOT_ALLOWED`                           | The model isn't enabled for your organization                        | Pick a model from your organization's allowed list, or ask your admin to enable it |
| 404 — `MODEL_NOT_FOUND`                             | The model name wasn't recognized                                     | Check the model ID for typos against [the model list](/models)                     |
| 402/429 — `usage_cap_exceeded`, `BUDGET_EXCEEDED`   | Your organization's spend cap was reached                            | Requests resume when the cap resets or an admin raises it (Wallet page)            |
| 429 — `rate_limit_exceeded`                         | Too many requests right now                                          | Wait a few seconds and retry — honors `Retry-After`; this passes on its own        |
| 5xx — `UPSTREAM_ERROR`, `TIMEOUT_ERROR`             | The AI provider is having trouble — not your setup                   | Retry in a few minutes; the SDKs retry these automatically                         |
| Anything else                                       | An unexpected failure                                                | Retry once, then contact support with the `requestId`                              |

<Note>
  **Tip:** every server-derived error carries a `requestId` — quote it
  to support and they can find the exact request. Full exception taxonomy in
  [Errors & retries](/api-reference/errors).
</Note>
