Not Organic Developers

Not Organic / Integration guides

Build on a shared account.

Connect identity, scoped permissions, and metered services without passing provider credentials to a client.

Before you connect

Not Organic is the shared account and hosted-service layer for Twyne, Keating, Interleave, and Stich. Integrations use scoped access tokens bound to a proof key. An ordinary OpenAI API key is not a Not Organic credential.

Confirm access and availability first.

This documentation is public; it does not establish open production enrollment. Obtain the appropriate product integration approval, confirm the API deployment is healthy, and use a test account before sending user data or paid requests.

AddressPurpose
https://api.notorganic.infoGateway base URL, without a trailing /v1 in SDK configuration.
https://id.notorganic.infoSign-in and authorization portal.
GET /healthzGateway store readiness. It is not a check of every upstream model or payment provider.

Choose your integration

Read a wallet from your server

The SDK lives at packages/sdk in this repository. With repository access, run bun install --frozen-lockfile and import @notorganic/sdk from a workspace package. Public package-registry availability is not assumed by this guide.

Your trusted backend must supply a fresh product assertion whose granted capabilities include wallet:read. The assertion signing key must be registered with the gateway; do not create a production signing key in a browser.

TypeScript · examples/read-wallet.ts
import {
  ServerClient,
  createDpopKeyPair,
  createDpopProofFactory,
  exchangeProductAssertion,
} from "@notorganic/sdk";

// Call on a trusted server with a fresh, authorized product assertion.
// Assertions are single-use and valid for no more than 60 seconds.
export async function readWallet(
  assertion: string,
  request: typeof fetch = globalThis.fetch,
) {
  const baseURL = "https://api.notorganic.info";
  const keyPair = await createDpopKeyPair();
  const token = await exchangeProductAssertion(
    baseURL,
    {
      assertion,
      dpop_jwk: keyPair.publicJwk,
      scope: "wallet:read",
    },
    { fetch: request },
  );

  const client = new ServerClient({
    baseURL,
    accessToken: token.access_token,
    dpopProof: createDpopProofFactory(keyPair),
    fetch: request,
  });

  return client.wallet.retrieve();
}

Download the TypeScript example. Call readWallet(freshAssertion) from your backend. The example exchanges once and immediately reads the wallet; it does not implement a long-lived token cache.

The returned access token lasts 300 seconds. For subsequent exchanges, mint a new assertion. Never reuse a consumed assertion or place tokens, assertions, or private keys in logs.

Make a metered request

After obtaining a token with the appropriate inference scope, create a ServerClient with that token and the matching DPoP proof factory. Set a spending reservation and an idempotency key explicitly.

TypeScript · metered request
const response = await client.responses.create(
  { model: "balanced", input: "Explain photosynthesis.", store: false },
  {
    maxCostMicrousd: 100_000, // $0.10 reservation
    idempotencyKey: crypto.randomUUID(),
  },
);

client here is authenticated with infer:balanced, rather than the wallet-only scope in the first example. Read how reservations and actual costs differ before exposing spending controls to users.