API Overview

Understand the current Apothic control plane, authentication model, and the recommended developer surfaces for apps, jobs, services, storage, and shared state.

Last updated: 4/23/2026
API Version: v0.1.0
apireferenceruntime

API Overview#

The main programmable Apothic surface today is the runtime control plane served from:

https://run.apothic.ai

Most users should access it through apothic-client, which provides a Python SDK and CLI for:

  • deploying apps
  • invoking functions
  • watching jobs and deployments
  • tailing deployment startup logs for services that expose startup_log_tail
  • running HTTP services
  • using stateful classes and sandboxes
  • managing storage and secrets
  • coordinating workers with queues and dictionaries

Recommended entry points#

Choose the interface that matches your workflow:

  • Python SDK for application code and automation
  • CLI for deploy, inspect, watch, and cleanup workflows
  • Dashboard for account, billing, and managed deployment flows

If you are building on the runtime directly, start with:

Runtime architecture#

The public runtime is the native Apothic control plane.

The important pieces are:

  • Fly hosts the control-plane API
  • SurrealDB stores deployments, functions, jobs, schedules, workers, secrets, volumes, and event rows
  • on-demand workers execute user workloads and connect back to the runtime over outbound machine sessions
  • storage is split across portable mounts and host-local fast paths rather than one universal bucket-only model

That architecture is why the API can expose one coherent resource surface while still supporting stateless jobs, long-lived services, stateful sandboxes, and host-affine vast_local storage.

Authentication#

Runtime requests are authenticated with an Apothic account API key.

The most common setup is:

export APOTHIC_API_KEY=your_apothic_api_key

The current client/runtime stack also supports:

  • APOTHIC_AUTH_TOKEN
  • APOTHIC_AUTH_HEADER
  • APOTHIC_BASE_URL

By default, apothic-client targets https://run.apothic.ai and automatically sends an Authorization: Bearer ... header when APOTHIC_API_KEY is set.

Account and billing model#

Runtime usage is tied to your Apothic account.

That means:

  • apps, deployments, and jobs are associated with the caller’s billing account
  • runtime charges draw down from your Apothic balance
  • you can add funds from the website billing dashboard before running billable workloads

For the current user-facing billing flow, see /dashboard/billing in the website.

Core resource types#

The current runtime surface is organized around a few core primitives.

Apps and deployments#

An App is the package you deploy. Each deploy creates a deployment record you can inspect, watch, stop, or delete later.

Typical operations include:

  • app.deploy()
  • RemoteFunction.from_name(...)
  • apothic app list
  • apothic deployment inspect ...
  • apothic deployment watch ... --snapshot

Functions and jobs#

Use @app.function(...) for remote compute. You can:

  • call it directly with remote()
  • create a background job with spawn()
  • stream typed execution events with job.watch() or remote_events(...)

Services#

Apothic also supports long-lived service shapes:

  • @app.endpoint(...)
  • @app.asgi(...)
  • @app.fastapi_endpoint(...)
  • @app.wsgi_app()
  • @app.web_server(...)

Classes and sandboxes#

The runtime also supports persistent instance-style resources through:

  • @app.cls(...)
  • app.sandbox(...)

These are useful when you need a sticky instance id, a persistent workspace, or repeated calls against one initialized resource.

Storage and secrets#

The current runtime surface also includes:

  • portable named volumes
  • host-affine vast_local volumes
  • explicit CloudBucketMount(...) specs for S3-compatible buckets
  • account-scoped secrets

Shared coordination#

The runtime exposes named shared primitives:

  • Queue
  • Dict

They support:

  • blocking reads
  • watch streams
  • claims, acknowledgements, renewals, and releases
  • key leases
  • compare-and-set updates
  • locks and leader election

Placement and capacity filters#

The client and runtime support two ways to describe capacity requirements.

The convenience path uses fields such as:

  • gpu
  • gpu_count
  • min_vram_gb
  • geolocation
  • max_cost_per_hour_usd
  • disk_gb
  • service_startup_timeout_s

The flexible path uses offer_filters, which accepts structured comparison operators:

  • eq
  • neq
  • gt
  • lt
  • gte
  • lte
  • in
  • notin

That means you can express ranges and richer capacity filters without waiting for the SDK to grow one-off named parameters for every metadata field.

Apothic Client reference section#

The site now also includes a dedicated apothic-client reference section for signatures and method-level lookup:

Event streams and watches#

The current control plane is stream-oriented in a few important places.

You can watch:

  • jobs
  • apps
  • deployments
  • queues
  • dictionaries

Snapshot-aware watch flows are available in both the SDK and CLI, which makes it easier to build dashboards, operators, and automation that reacts to live state.

Generated functions#

apothic-client also supports generated implementations through @apothic.liv(...) and LivConfig.

The currently supported mode is deploy-time freeze, which means:

  1. the generated implementation is materialized before deploy
  2. the generated module is packaged into the app archive
  3. the remote runtime executes the frozen result as normal Python

CLI example#

apothic deploy app.py
apothic run infer --app-name demo --payload '{"args":["hello"],"kwargs":{}}' --watch
apothic logs jobs:123
apothic deployment logs deployments:123
apothic deployment watch deployments:123 --snapshot
apothic queue watch image-jobs --snapshot

Python example#

from apothic import App, RemoteFunction

app = App("hello-world")


@app.function(cpu=1, memory_mb=512, timeout_s=60)
def greet(name: str) -> str:
    return f"hello, {name}"


deployment_id = app.deploy()
remote = RemoteFunction.from_name("hello-world", "greet")
print(deployment_id)
print(remote.remote("world"))