Organization context & pagination
Most API keys are created under a single organization in the dashboard; authorization and roles are evaluated in that org’s context. Some accounts participate in multiple organizations. Wire-level list endpoints then combine organization selection (X-Org and related query fields) with pagination query parameters described in the canonical OpenAPI bundle.
This page ties those concepts to each SDK. For installation and credentials, start with Authentication.
Organization context
Section titled “Organization context”| Concept | Details |
|---|---|
| Key issuance | Keys are minted while an organization is selected in the dashboard; role checks apply in that org. See API keys. |
| Multi-org users | Call GET /orgs (list orgs your principal can access) and choose a target org id before hitting org-scoped routes. |
X-Org header | Many operations are documented as “for the organization context (X-Org)”. Pass the organization id (ULID string) in this header when the operation requires an explicit org. OpenAPI lists which operations need it — for example list_devices (GET /devices); see the API reference and packages/api-spec/openapi.json in the repository. |
orgId query | Some list surfaces accept an orgId filter in addition to X-Org. Prefer matching the same org id in both when your generator or SDK exposes both. |
Errors: Missing or invalid org context typically surfaces as 403 Forbidden or 404 depending on the route and server rules, in addition to the usual 401 when the key is invalid.
Pagination on list endpoints
Section titled “Pagination on list endpoints”The public API describes list operations with:
output_options—MultiResourceOutputOptionsQueryin the OpenAPI bundle (include_deleted,include_metadata,only_deleted— all required on the wire in the published schema).pagination—PaginationQuery:limit(page size, server-enforced max typically 200) andoffset(items to skip).
Response shape for paginated JSON bodies is typically PaginatedResponse: items (array) and total (count). Some SDK-level wrappers may expose cursor-style helpers on top of the same routes; where that applies, see Python — Resources for iteration patterns.
When in doubt, use the interactive API reference for the exact parameters and schemas of the operation you are calling.
Examples
Section titled “Examples”List devices in an organization
Section titled “List devices in an organization”devices.list accepts optional org_id, limit, and cursor kwargs; the bridge forwards query parameters to GET /devices.
rows = await client.devices.list( org_id="01HORG00000000000000000000", limit=50,)# `rows` follows the API response body (shape depends on route — often a list or paginated object).For large org listings and other resources, combine limit with the pagination fields returned by the API (for example a next_cursor when the service emits one — see Resources).
The generated client requires X-Org, OutputOptions, and Pagination for ListDevices.
import ( openapiclient "github.com/tomers/openapp-sdk/go")
resp, httpResp, err := client.DevicesAPI.ListDevices(ctx). XOrg("01HORG00000000000000000000"). OutputOptions(*openapiclient.NewMultiResourceOutputOptionsQuery(false, false, false)). Pagination(openapiclient.PaginationQuery{Limit: openapiclient.PtrInt32(50), Offset: openapiclient.PtrInt32(0)}). Execute()if err != nil { return err}defer httpResp.Body.Close()// resp is []openapiclient.DeviceResponseHigh-level DevicesClient::list returns a decoded JSON array and does not attach X-Org. For routes that require org context, use the shared Transport engine with a RequestSpec — mirroring the pattern exercised in packages/sdk/rust/tests/gherkin_tier1.rs:
use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::Value;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let org_id = "01HORG00000000000000000000".to_string();let body: Value = client .transport() .request_json(RequestSpec { method: Method::GET, path: "/devices", query: &[("orgId", Some(org_id.clone()))], extra_headers: &[("X-Org", org_id)], ..Default::default() }) .await?;Extend query with output_options and pagination encoding expected by your deployment if the server rejects bare GET /devices calls.
The Node AsyncClient currently exposes a small façade. listDevices in the Node package calls GET /devices and does not send X-Org; the parameter is reserved for future alignment. For full control (headers and query), use the Python or Go SDK, or call the REST API directly with the same auth headers as in Authentication.
List organizations (discovery)
Section titled “List organizations (discovery)”page = await client.orgs.list(limit=50)for org in page.get("items", []): print(org.get("id"), org.get("name"))ListOrgs requires OutputOptions and Pagination:
import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
page, httpResp, err := client.OrgsAPI.ListOrgs(ctx). OutputOptions(*openapiclient.NewMultiResourceOutputOptionsQuery(false, false, false)). Pagination(openapiclient.PaginationQuery{Limit: openapiclient.PtrInt32(50), Offset: openapiclient.PtrInt32(0)}). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = pageuse openapp_sdk::Client;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let orgs = client.orgs().list().await?;If you need full pagination parity with OpenAPI, issue a transport-level GET /orgs with explicit output_options / pagination query serialization.
import { AsyncClient } from "@tomers/openapp-sdk";
const client = new AsyncClient("https://api.openapp.house/api/v1_openapp_YOUR_SECRET");const orgs = await client.listOrgs();The returned value is parsed JSON from GET /orgs; narrow the type in your application as needed.
Related
Section titled “Related”- Authentication — constructing clients and bearer tokens.
- Python — Resources — sub-clients, payload conventions, and pagination snippets.
- API reference — authoritative parameters per operation.