Account API

The account API manages your algal.cloud account: API keys, habitats, credits and usage. This page is generated from the API contract each time the site is built.

Early access (test mode). Payments run in Stripe test mode and no card is charged. Accounts, limits and prices may change before launch.

Paid endpoints

A paid endpoint is published at api.algal.cloud/e/<org>/<project>, and its public page lives at /e/<org>/<project> on this site. Callers POST a JSON body; the 402 response carries a Stripe test-mode checkout link for an invocation ticket, and the paid ticket goes in the x-algal-ticket header. Each ticket covers a pack of invocations at the price the owner set. A caller with an account key (Authorization: Bearer $ALGAL_KEY, billing scope) is charged from their balance instead, and the 202 response includes the ticket for the rest of the pack. Owners manage endpoints, earnings and payouts with the routes below or the CLI.

Answer calls with a program

Bind a program to an endpoint and each paid call runs it once. Upload the program's bundle to the habitat, then store the binding in the habitat slot endpoint-program.<mailbox>, using the mailbox name the endpoint was created with:

curl -X PUT "$ALGAL_API/v1/habitats/$HABITAT/slots/endpoint-program.answers" \
  -H "Authorization: Bearer $ALGAL_KEY" -H "Content-Type: application/json" \
  -d '{"value":{"manifest":"sha256:<program digest>"}}'

The caller's JSON input arrives on the program's input cell, and the program's value output comes back as {"value": ...}. A run that fails returns {"error": {"code", "message"}} instead. Name a deployment in place of manifest to follow the program as it evolves, and add an executor for programs that call a model. Without a binding, calls wait in the mailbox for a process you run yourself.

Routes

Send the key as Authorization: Bearer $ALGAL_KEY. Generated from packages/protocol/src/account-api.ts (sha256 a709fb7e3a47).

MethodPathWhat it does
GET/v1/account
POST/v1/account/tenant(header Idempotency-Key) → 201
GET/v1/account/keys
POST/v1/account/keys→ 201. The plaintext key appears only here, once.
POST/v1/account/keys/:keyId/revoke→ 200
GET/v1/account/habitats
POST/v1/account/credits/checkout
GET/v1/account/usage
GET/v1/account/orgthe account's org slug, or `org: null`.
POST/v1/account/org;PATCH /v1/account/org (rename while unbound).
GET/v1/account/endpointsitem.
POST/v1/account/endpoints→ 201.
PATCH/v1/account/endpoints/:projectomitted fields are unchanged.
GET/v1/account/earningsthe owner's journaled ledger view (W3-PAY).
POST/v1/account/earnings/applymove available earnings into the
POST/v1/account/payouts/linkConnect Express onboarding URL for the
POST/v1/account/payoutstransfer available earnings to the bound
POST/v1/account/task-campaigns
POST/v1/account/org
PATCH/v1/account/org

Error codes

Errors come back as {"error":{"code","message"}}. The codes are:

  • UNAUTHORIZED
  • NOT_ADMITTED
  • EMAIL_UNVERIFIED
  • RATE_LIMITED
  • TENANT_CAP_REACHED
  • TENANT_EXISTS
  • ACCOUNT_API_DISABLED
  • UNAVAILABLE
  • PARSE_FAILED
  • CONFLICT
  • NOT_FOUND
  • ACCOUNT_CREATE_FAILED
  • ACCOUNT_PENDING

Types

AccountErrorCode

export type AccountErrorCode = typeof ACCOUNT_ERROR_CODES[number];

AccountApiErrorBody

export type AccountApiErrorBody = {
    error: {
        code: AccountErrorCode;
        message: string;
    };
};

AccountAdmission

--- shapes -------------------------------------------------------------

export type AccountAdmission = "admitted" | "waitlisted";

AccountTenantView

export type AccountTenantView = {
    tenantId: TenantId;
    label: string;
    createdAt: number;
};

AccountView

GET /v1/account

export type AccountView = {
    subject: string;
    email: string;
    admission: AccountAdmission;
    tenant: AccountTenantView | null;
};

AccountTenantCreateRequest

POST /v1/account/tenant (header Idempotency-Key) → 201

export type AccountTenantCreateRequest = {
    label: string;
};

AccountTenantCreateResponse

export type AccountTenantCreateResponse = {
    tenantId: TenantId;
};

AccountKeyView

GET /v1/account/keys

export type AccountKeyView = {
    keyId: string;
    label: string;
    scopes: Scope[];
    createdAt: number;
    expiresAt: number | null;
    lastFour: string;
};

AccountKeysResponse

export type AccountKeysResponse = {
    keys: AccountKeyView[];
};

AccountKeyCreateRequest

POST /v1/account/keys → 201. The plaintext key appears only here, once.

export type AccountKeyCreateRequest = {
    label: string;
    scopes: Scope[];
    ttlDays?: number;
};

AccountKeyCreateResponse

export type AccountKeyCreateResponse = {
    keyId: string;
    apiKey: ApiKey;
};

AccountKeyRevokeResponse

POST /v1/account/keys/:keyId/revoke → 200

export type AccountKeyRevokeResponse = {
    keyId: string;
    revokedAt: number;
};

AccountHabitatsResponse

GET /v1/account/habitats

export type AccountHabitatsResponse = {
    habitats: HabitatView[];
    next?: string;
};

AccountCreditCheckoutRequest

POST /v1/account/credits/checkout

export type AccountCreditCheckoutRequest = {
    amountMicrocents: number;
};

AccountCreditCheckoutResponse

export type AccountCreditCheckoutResponse = {
    checkoutUrl: string;
};

AccountUsageResponse

GET /v1/account/usage

export type AccountUsageResponse = {
    balanceMicrocents: number;
    periodSpendMicrocents: number;
};

AccountOrgResponse

GET /v1/account/org — the account's org slug, or `org: null`.

export type AccountOrgResponse = {
    org: AccountOrgView | null;
};

AccountOrgView

export type AccountOrgView = {
    slug: string;
    createdAt: number;
};

AccountOrgRequest

POST /v1/account/org; PATCH /v1/account/org (rename while unbound).

export type AccountOrgRequest = {
    slug: string;
};

EndpointState

Endpoint lifecycle: live serves paid calls; paused refuses them; retired is terminal — a retired name can never be re-created or reactivated.

export type EndpointState = "live" | "paused" | "retired";

AccountEndpointView

GET /v1/account/endpoints item.

export type AccountEndpointView = {
    org: string;
    project: string;
    habitatId: string;
    mailbox: string;
    priceMicrocents: number;
    packSize: number;
    state: EndpointState;
    createdAt: number;
    updatedAt: number;
};

AccountEndpointCreateRequest

POST /v1/account/endpoints → 201.

export type AccountEndpointCreateRequest = {
    project: string;
    habitatId: string;
    mailbox: string;
    priceMicrocents: number;
    packSize: number;
};

AccountEndpointPatchRequest

PATCH /v1/account/endpoints/:project — omitted fields are unchanged. `state` may be "live", "paused" or "retired"; retired is terminal.

export type AccountEndpointPatchRequest = {
    priceMicrocents?: number;
    packSize?: number;
    state?: EndpointState;
};

AccountEndpointsResponse

GET /v1/account/endpoints

export type AccountEndpointsResponse = {
    endpoints: AccountEndpointView[];
    next?: string;
};

AccountEarningsEntry

GET /v1/account/earnings — the owner's journaled ledger view (W3-PAY). `availableMicrocents` is what apply/payout may draw: accrued − applied − paidOut − clawedBack.

export type AccountEarningsEntry = {
    seq: number;
    kind: string;
    microcents: number;
    ref: string;
    at: number;
};

AccountEarningsResponse

export type AccountEarningsResponse = {
    accruedMicrocents: number;
    appliedMicrocents: number;
    paidOutMicrocents: number;
    clawedBackMicrocents: number;
    availableMicrocents: number;
    connect?: {
        accountId: string;
        chargesEnabled: boolean;
        payoutsEnabled: boolean;
    };
    entries: AccountEarningsEntry[];
    next?: number;
};

AccountEarningsApplyRequest

POST /v1/account/earnings/apply — move available earnings into the spendable broker balance. Idempotent on the Idempotency-Key header.

export type AccountEarningsApplyRequest = {
    amountMicrocents: number;
};

AccountEarningsApplyResponse

export type AccountEarningsApplyResponse = {
    appliedMicrocents: number;
    balanceMicrocents?: number;
    duplicate?: boolean;
};

AccountPayoutLinkResponse

POST /v1/account/payouts/link — Connect Express onboarding URL for the account's bound (or newly created) Stripe account.

export type AccountPayoutLinkResponse = {
    url: string;
    accountId: string;
};

AccountPayoutRequest

POST /v1/account/payouts — transfer available earnings to the bound Connect account. `amountMicrocents` omitted pays the full available balance (floored to whole cents). Idempotent on Idempotency-Key.

export type AccountPayoutRequest = {
    amountMicrocents?: number;
};

AccountPayoutResponse

export type AccountPayoutResponse = {
    paidOutMicrocents: number;
    transferId?: string;
    duplicate?: boolean;
};

Platform limits

Generated from packages/protocol/src/index.ts. They apply to every early-access account and may change before launch.

LimitValue
Habitats per account64
Processes per habitat1,024
Mailboxes per habitat64
Message size64,000 bytes
Program bundle size8 MiB
Generations per process64
Wall time per step25 s