API Keys

Create Organization API Key

Programmatically create an API key owned by an organization.

POST /api/organizations/:organizationId/api-keys

Creates an API key owned by the organization itself, rather than by your user account. The key authenticates as the organization (org-admin authority over its sites), so it survives member departures, and its plan gating, rate limits, and key-count limit all follow the owning organization's subscription. Organization keys are issued with the rb_org_ prefix.

You must be an owner or admin of the target organization. This endpoint accepts your dashboard session or an unrestricted (full-access) user API key — scoped keys and organization keys are rejected, so an organization key cannot mint other keys.

Path Parameters

Prop

Type

Request Body

Prop

Type

Response

Returns the created API key object. The full key value carries the rb_org_ prefix.

Prop

Type

Note: Additional fields may be present in the response object.

Request
curl -X POST "https://app.rybbit.io/api/organizations/org_123/api-keys" \
  -H "Cookie: better-auth.session_token=YOUR_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI pipeline", "expiresIn": 2592000}'
Request
const response = await fetch(
  'https://app.rybbit.io/api/organizations/org_123/api-keys',
  {
    method: 'POST',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'CI pipeline',
      expiresIn: 2592000
    })
  }
);

const data = await response.json();
Request
import requests

response = requests.post(
    'https://app.rybbit.io/api/organizations/org_123/api-keys',
    json={
        'name': 'CI pipeline',
        'expiresIn': 2592000
    },
    headers={
        'Cookie': 'better-auth.session_token=YOUR_SESSION_TOKEN'
    }
)

data = response.json()
Request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://app.rybbit.io/api/organizations/org_123/api-keys");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'name' => 'CI pipeline',
    'expiresIn' => 2592000
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Cookie: better-auth.session_token=YOUR_SESSION_TOKEN',
    'Content-Type: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
Request
require 'net/http'
require 'json'

uri = URI("https://app.rybbit.io/api/organizations/org_123/api-keys")
req = Net::HTTP::Post.new(uri)
req['Cookie'] = 'better-auth.session_token=YOUR_SESSION_TOKEN'
req['Content-Type'] = 'application/json'
req.body = {
  name: 'CI pipeline',
  expiresIn: 2592000
}.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
Request
body := bytes.NewBuffer([]byte(`{
  "name": "CI pipeline",
  "expiresIn": 2592000
}`))
req, _ := http.NewRequest("POST", "https://app.rybbit.io/api/organizations/org_123/api-keys", body)
req.Header.Set("Cookie", "better-auth.session_token=YOUR_SESSION_TOKEN")
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)
Request
let client = reqwest::Client::new();
let res = client
    .post("https://app.rybbit.io/api/organizations/org_123/api-keys")
    .header("Cookie", "better-auth.session_token=YOUR_SESSION_TOKEN")
    .json(&serde_json::json!({
        "name": "CI pipeline",
        "expiresIn": 2592000
    }))
    .send()
    .await?;

let data: serde_json::Value = res.json().await?;
Request
HttpClient client = HttpClient.newHttpClient();
String json = "{\"name\": \"CI pipeline\", \"expiresIn\": 2592000}";
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.rybbit.io/api/organizations/org_123/api-keys"))
    .header("Cookie", "better-auth.session_token=YOUR_SESSION_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Request
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Cookie", "better-auth.session_token=YOUR_SESSION_TOKEN");

var content = new StringContent(
    "{\"name\": \"CI pipeline\", \"expiresIn\": 2592000}",
    Encoding.UTF8,
    "application/json"
);

var response = await client.PostAsync("https://app.rybbit.io/api/organizations/org_123/api-keys", content);
var data = await response.Content.ReadAsStringAsync();
The full key value is returned only once, at creation. Store it securely — it cannot be retrieved again.
Response
{
  "id": "key_8f3a1b2c4d5e6f7g",
  "key": "rb_org_xxxxxxxxxxxxxxxxxxxx",
  "name": "CI pipeline",
  "start": "rb_org_xxxx",
  "prefix": "rb_org_",
  "referenceId": "org_123",
  "userId": "user_2a9b8c7d6e5f4g3h",
  "enabled": true,
  "expiresAt": "2026-07-25T12:00:00.000Z",
  "createdAt": "2026-06-25T12:00:00.000Z",
  "updatedAt": "2026-06-25T12:00:00.000Z",
  "rateLimitEnabled": true,
  "rateLimitMax": 200,
  "rateLimitTimeWindow": 60000
}
On Rybbit Cloud, organization API keys require the organization to be on a Standard or Pro plan; free/basic plans receive HTTP 403. Each organization also has a plan-based key-count limit — creating a key past the limit returns HTTP 403.