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

# Read the Ruba API Contract

> Choose an environment and authority boundary, then make, page, and retry requests safely.

export const RubaSocials = () => {
  if (typeof document === "undefined") {
    return null;
  }
  const inject = () => {
    const footer = document.getElementById("footer");
    if (!footer || document.getElementById("ruba-socials")) {
      return false;
    }
    const isDark = document.querySelector("html.dark") || document.querySelector('html[class*="dark"]');
    const lineColor = isDark ? "#383838" : "#e8e8ed";
    const iconColor = isDark ? "#8e8e93" : "#86868b";
    const markColor = isDark ? "#ffffff" : "#08080c";
    const hoverColor = "#0071e3";
    const div = document.createElement("div");
    div.id = "ruba-socials";
    div.style.cssText = `display:flex;align-items:center;gap:20px;padding-top:20px;margin-top:20px;border-top:1px solid ${lineColor};width:100%`;
    const logo = `<a href="https://getruba.com" style="display:inline-flex;height:24px;align-items:center;gap:8px;text-decoration:none;color:${markColor};line-height:1;"><svg width="24" height="24" viewBox="0 0 120 120" aria-hidden="true" style="display:block;flex:none;"><g transform="translate(2.5 0)"><path d="M19 25h59L65.43 47H19a4 4 0 0 1-4-4V29a4 4 0 0 1 4-4Z" fill="${markColor}"/><path d="M19 73h31.57L38 95H19a4 4 0 0 1-4-4V77a4 4 0 0 1 4-4Z" fill="${markColor}"/><path d="M85 25h25L70 95H45Z" fill="#007AFF"/></g></svg><span style="display:inline-flex;height:24px;align-items:center;font-weight:600;font-size:15px;color:${markColor};letter-spacing:-0.01em;line-height:1;">Ruba</span></a>`;
    const spacer = `<div style="flex:1"></div>`;
    const ig = `<a href="https://instagram.com/getruba" target="_blank" rel="noopener" aria-label="Instagram" style="display:flex;align-items:center;color:${iconColor};transition:color 0.15s ease;" onmouseover="this.style.color='${hoverColor}'" onmouseout="this.style.color='${iconColor}'"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/></svg></a>`;
    const li = `<a href="https://linkedin.com/company/getruba" target="_blank" rel="noopener" aria-label="LinkedIn" style="display:flex;align-items:center;color:${iconColor};transition:color 0.15s ease;" onmouseover="this.style.color='${hoverColor}'" onmouseout="this.style.color='${iconColor}'"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg></a>`;
    const x = `<a href="https://x.com/getruba" target="_blank" rel="noopener" aria-label="X" style="display:flex;align-items:center;color:${iconColor};transition:color 0.15s ease;" onmouseover="this.style.color='${hoverColor}'" onmouseout="this.style.color='${iconColor}'"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg></a>`;
    const github = `<a href="https://github.com/rubadot" target="_blank" rel="noopener" aria-label="GitHub" style="display:flex;align-items:center;color:${iconColor};transition:color 0.15s ease;" onmouseover="this.style.color='${hoverColor}'" onmouseout="this.style.color='${iconColor}'"><svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .7a11.5 11.5 0 0 0-3.64 22.4c.58.1.79-.25.79-.56v-2.24c-3.22.7-3.9-1.37-3.9-1.37-.53-1.34-1.29-1.7-1.29-1.7-1.05-.72.08-.71.08-.71 1.16.08 1.78 1.2 1.78 1.2 1.04 1.77 2.72 1.26 3.38.96.1-.75.4-1.26.74-1.55-2.57-.3-5.27-1.29-5.27-5.69 0-1.26.45-2.29 1.19-3.09-.12-.29-.52-1.47.11-3.05 0 0 .97-.31 3.16 1.18A10.96 10.96 0 0 1 12 6.09c.98 0 1.94.13 2.86.39 2.2-1.49 3.16-1.18 3.16-1.18.63 1.58.23 2.76.11 3.05.74.8 1.19 1.83 1.19 3.09 0 4.42-2.7 5.39-5.28 5.68.42.36.79 1.06.79 2.14v3.28c0 .31.21.67.8.56A11.5 11.5 0 0 0 12 .7Z"/></svg></a>`;
    div.innerHTML = logo + spacer + ig + li + x + github;
    footer.appendChild(div);
    return true;
  };
  if (!document.documentElement.dataset.rubaSocialsObserver) {
    document.documentElement.dataset.rubaSocialsObserver = "true";
    const observer = new MutationObserver(() => {
      if (!document.getElementById("ruba-socials")) {
        inject();
      }
    });
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }
  setTimeout(() => {
    if (!inject()) {
      const interval = setInterval(() => {
        if (inject()) {
          clearInterval(interval);
        }
      }, 500);
      setTimeout(() => clearInterval(interval), 10000);
    }
  }, 300);
  return null;
};

<link rel="stylesheet" href="/style.css" />

<RubaSocials />

The reference is organized around the path money and access take through Ruba. Start with the authority your code should have, then move into the resource group that owns the state you need.

## Choose the authority boundary first

Ruba exposes two API surfaces. They share the same versioned base URL but represent different actors.

| Surface             | Credential                               | What it can see                                                  |
| ------------------- | ---------------------------------------- | ---------------------------------------------------------------- |
| Organization API    | Organization Access Token or OAuth token | Resources permitted by the token scopes across the organization. |
| Customer Portal API | Customer access token                    | Data and actions belonging to the authenticated customer.        |

Use an organization credential only from trusted server-side code. When browser code needs customer-owned billing data, create a [customer session](/api-reference/customer-portal/sessions/create) on your server and pass its customer access token to the portal API.

```http Organization request theme={"system"}
Authorization: Bearer ruba_oat_xxxxxxxxxxxxxxxxx
```

<Warning>
  Never place an Organization Access Token in browser code, public source,
  analytics payloads, or application logs.
</Warning>

## Pick the environment deliberately

| Mode       | Root                                 | Use it for                                   |
| ---------- | ------------------------------------ | -------------------------------------------- |
| Sandbox    | `https://sandbox-api.getruba.com/v1` | Integration builds and test data.            |
| Production | `https://api.getruba.com/v1`         | Live organizations, customers, and payments. |

Sandbox and production do not share organizations, records, or credentials. Create a token in each environment and keep the variables separate. See [Build Safely in the Sandbox](/integrate/sandbox).

## Follow the request cycle

Every endpoint page is arranged in the same working order:

<Steps>
  <Step title="Read the intent">
    Confirm that the operation owns the state transition or lookup your integration needs.
  </Step>

  <Step title="Check the access boundary">
    Match the credential type and required scopes before constructing the request.
  </Step>

  <Step title="Build the request">
    Select the environment, fill path and query values, and supply the documented body when one is required.
  </Step>

  <Step title="Inspect every documented result">
    Use the success schema for normal processing and handle the listed error responses explicitly.
  </Step>
</Steps>

The **Try it** workspace keeps this sequence together. It does not change the endpoint contract; it gives you an interactive way to assemble the same request shown in the code examples.

## Make the first read

The following request lists catalog items without changing organization state.

<CodeGroup>
  ```bash Production theme={"system"}
  curl "https://api.getruba.com/v1/products/?page=1&limit=10" \
    -H "Authorization: Bearer $RUBA_OAT" \
    -H "Accept: application/json"
  ```

  ```bash Sandbox theme={"system"}
  curl "https://sandbox-api.getruba.com/v1/products/?page=1&limit=10" \
    -H "Authorization: Bearer $RUBA_OAT_SANDBOX" \
    -H "Accept: application/json"
  ```
</CodeGroup>

## Walk a collection without losing your place

Collection operations accept `page` and `limit`.

| Input   | Default | Maximum | Meaning                                   |
| ------- | ------- | ------- | ----------------------------------------- |
| `page`  | `1`     | —       | One-based page to read.                   |
| `limit` | `10`    | `100`   | Maximum records returned by that request. |

The response includes:

| Field         | Meaning                                        |
| ------------- | ---------------------------------------------- |
| `total_count` | Records matching the request across all pages. |
| `max_page`    | Last available page for the selected limit.    |

Continue until the requested page reaches `max_page`. Official SDK pagination helpers can perform this iteration for you.

## Budget requests and retries

Rate limits are applied per organization, customer, or OAuth client:

* Production: **500 requests per minute**.
* Sandbox: **100 requests per minute**.
* Unauthenticated license-key validation, activation, and deactivation: **3 requests per second** in either environment.

When the budget is exhausted, Ruba returns `429 Too Many Requests`. Wait for the number of seconds supplied in `Retry-After` before sending the next attempt.

## Start from an official SDK

<CodeGroup>
  ```ts TypeScript theme={"system"}
  import { Ruba } from "@getruba/sdk";

  const ruba = new Ruba({
    accessToken: process.env.RUBA_ACCESS_TOKEN!,
    server: "sandbox",
  });
  ```

  ```py Python theme={"system"}
  import os
  from ruba import Ruba

  client = Ruba(
      access_token=os.environ["RUBA_ACCESS_TOKEN"],
      server="sandbox",
  )
  ```

  ```go Go theme={"system"}
  import rubago "github.com/rubadot/ruba-go"

  client := rubago.New(
    rubago.WithServer("sandbox"),
    rubago.WithSecurity(os.Getenv("RUBA_ACCESS_TOKEN")),
  )
  ```

  ```php PHP theme={"system"}
  $client = Ruba\Ruba::builder()
      ->setServer('sandbox')
      ->setSecurity(getenv('RUBA_ACCESS_TOKEN'))
      ->build();
  ```
</CodeGroup>

## Enter through the transaction journey

<CardGroup cols={2}>
  <Card title="Create a sale" icon="cart-shopping" href="/api-reference/products/list">
    Catalog, checkout sessions, buy links, discounts, and checkout fields.
  </Card>

  <Card title="Manage recurring revenue" icon="repeat" href="/api-reference/subscriptions/list">
    Subscriptions, usage events, meters, balances, and seat assignments.
  </Card>

  <Card title="Model customer access" icon="key" href="/api-reference/benefits/list">
    Customer records, members, benefits, licenses, and files.
  </Card>

  <Card title="React to state changes" icon="webhook" href="/api-reference/webhooks/checkout.created">
    Webhook payloads for customer, billing, fulfillment, and organization events.
  </Card>
</CardGroup>
