Skip to content

REST API Endpoints

Complete documentation of all HTTP REST endpoints in the GoFigr server API.

Base URL: https://api.gofigr.io
Supported API Versions: v1, v1.1, v1.2, v1.3, v1.4, v1.4.1

All endpoints are versioned: /api/{version}/resource/

Authentication:

  • JWT Bearer token: Authorization: Bearer {access_token}
  • API Key: Authorization: Token {api_key}

  1. Authentication
  2. Common Resource Behavior
  3. Bootstrap
  4. API Info
  5. Site Settings
  6. Organizations
  7. Workspaces
  8. Analyses
  9. Figures
  10. Figure Revisions
  11. Assets
  12. Asset Revisions
  13. External Data
  14. Stories
  15. Comments
  16. Reactions
  17. Deep Insight (AI)
  18. Search
  19. Managed Compute
  20. Tasks
  21. Users
  22. Plans
  23. API Keys
  24. SSH Keys
  25. Git Repository
  26. Data Upload
  27. Invitations
  28. Billing
  29. Auth0
  30. Short IDs
  31. AI Usage
  32. Metadata Proxy
  33. API Version History

POST /api/token/

Authenticates user and returns access/refresh token pair.

Request Body:

{
"username": "string",
"password": "string",
"remember_me": true // optional, extends token lifetime
}

Response: 200 OK

{
"access": "string",
"refresh": "string"
}

POST /api/token/refresh/

Request Body:

{
"refresh": "string"
}

Response: 200 OK

{
"access": "string"
}

POST /api/password_reset/

Request Body:

{
"email": "string"
}

The core resources — Organizations, Workspaces, Analyses, Figures, Figure Revisions, Assets, Asset Revisions, Stories, and External Data — are all backed by the same viewset machinery and therefore share a common set of CRUD routes, sub-actions, and query parameters. Rather than repeat them under every resource, they are described once here. Resource-specific fields and extra actions are documented in each section below.

For a resource mounted at /{resource}/:

GET /api/{version}/{resource}/ # List (where supported)
POST /api/{version}/{resource}/ # Create → 201, 409 on duplicate client_id
GET /api/{version}/{resource}/{api_id}/ # Retrieve
PUT /api/{version}/{resource}/{api_id}/ # Full update
PATCH /api/{version}/{resource}/{api_id}/ # Partial update
DELETE /api/{version}/{resource}/{api_id}/ # Delete → 204

Objects are addressed by their api_id (a UUID). Permissions are enforced per action (VIEW, CREATE, UPDATE, DELETE, MANAGE, SHARE). Moving an object to a new parent (e.g. changing a figure’s analysis) on update requires move permission and is rejected with 400 if the type is not movable.

Available on every core resource ({api_id} detail routes):

GET /api/{version}/{resource}/{api_id}/size/ # → { "size_bytes": int }
GET /api/{version}/{resource}/{api_id}/children/ # → [ { "entity_type", "api_id" }, ... ] (recursive)
GET /api/{version}/{resource}/{api_id}/thumbnail/ # → { "format", "thumbnail" } (base64)
GET /api/{version}/{resource}/{api_id}/log/ # Activity log for the entity
GET /api/{version}/{resource}/{api_id}/log/{log_id}/ # Single enhanced log item
GET /api/{version}/{resource}/{api_id}/share/user/ # List users the object is shared with
POST /api/{version}/{resource}/{api_id}/share/user/ # { "username", "sharing_enabled" }
GET /api/{version}/{resource}/{api_id}/share/link/ # Link-sharing status
POST /api/{version}/{resource}/{api_id}/share/link/ # { "enabled": bool }
  • thumbnail/{size}/ — an optional size segment scales the thumbnail. Pass ?dl=1 (or an Accept: image/* header) to receive raw PNG bytes instead of JSON.
  • log/ — supports deep=true (full activity items, paginated), exclude_deleted=true, deduplicate=true, offset, and limit.
Parameter Applies to Effect
silent=true create, update, delete Mark the resulting activity-log entry as silent (still recorded, but hidden from most activity views)
dl=1 thumbnail/ Return binary PNG instead of JSON

All core resources include these read-only fields in their serialized form:

  • api_id, entity_type, size_bytes
  • created_by, updated_by (usernames), created_on, updated_on, last_activity_on
  • created_on_behalf, created_on_behalf_name, created_on_behalf_email (v1.3+)

GET /api/{version}/bootstrap/

Returns all data needed for initial frontend load in a single request, eliminating multiple round trips.

Response: 200 OK

{
"user": {...},
"workspaces": [...],
"settings": {...},
"info": {
"api_version": "string"
}
}

GET /api/{version}/info/

Public endpoint (no authentication required) describing the running server.

Response: 200 OK

{
"environment": "string",
"server_version": "string",
"started": "datetime",
"api_versions": ["v1", "v1.1", "v1.2", "v1.3", "v1.4", "v1.4.1"],
"your_ip": "string",
"ai_enabled": true
}

When Auth0 is configured, the response also includes auth0_domain, auth0_spa_client_id, auth0_cli_client_id, and auth0_audience.


GET /api/{version}/settings/

Returns the singleton site-settings object (feature flags, AI configuration, limits). Includes a read-only ai_supported_models list of available AI models.


Organizations group workspaces and manage shared subscriptions, billing, and membership.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, name, description, logo (base64 PNG, nullable), allow_link_sharing, allow_per_workspace_storage_settings, workspaces (read-only, shallow), plus the common timestamp fields.

POST /api/{version}/organization/

Request Body:

{
"name": "string",
"description": "string"
}
GET /api/{version}/organization/{api_id}/members/
POST /api/{version}/organization/{api_id}/members/add/
POST /api/{version}/organization/{api_id}/members/remove/
POST /api/{version}/organization/{api_id}/members/change/

Manage organization membership. members/ returns [{ "username", "membership_type" }]. Requires MANAGE.

GET /api/{version}/organization/{api_id}/subscription/
POST /api/{version}/organization/{api_id}/subscription/
PATCH /api/{version}/organization/{api_id}/subscription/

Get or change the organization’s plan, or toggle compute_overages_enabled. Requires MANAGE.

GET /api/{version}/organization/{api_id}/storage/
POST /api/{version}/organization/{api_id}/storage/
POST /api/{version}/organization/{api_id}/storage/test/

Configure a custom (BYO) storage backend. storage/test/ validates vendor/credentials without saving.

GET /api/{version}/organization/{api_id}/invitations/

Lists valid pending invitations for the organization. Requires MANAGE. See Invitations for create/accept.

GET /api/{version}/organization/{api_id}/compute_usage/?period=YYYY-MM

Billable managed-compute cost summary for the given month (defaults to month-to-date). Requires MANAGE.


Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, name, description, workspace_type, organization, size_bytes (read-only), compute_enabled (read-only), and — in the full serializer — read-only nested analyses, assets, and stories. The list endpoint returns a lightweight representation in v1.3+.

GET /api/{version}/workspace/

Lists all workspaces the user has access to (directly or via an organization).

GET /api/{version}/workspace/{api_id}/
POST /api/{version}/workspace/

Request Body:

{
"name": "string",
"description": "string",
"workspace_type": "secondary"
}

Primary workspaces are assigned at user creation and cannot be created through the API.

GET /api/{version}/workspace/{api_id}/overview/

Returns aggregated counts for the workspace.

Response: 200 OK

{
"analysis_count": 10,
"figure_count": 45,
"asset_count": 5,
"story_count": 3,
"active_this_week": 2
}
GET /api/{version}/workspace/{api_id}/dashboard/

Returns all data needed for the home view in a single request.

Query Parameters:

  • activity_limit (integer): Number of activity items (default: 10, max: 50)
  • exclude_deleted (boolean): Exclude deleted items from activity log
  • deduplicate (boolean): Collapse activity to the newest entry per target

Response: 200 OK

{
"workspace": {...},
"overview": {...},
"activity_log": {
"items": [...],
"has_more": true,
"total_count": 100,
"fetched_count": 10
},
"stories": [...]
}
GET /api/{version}/workspace/{api_id}/recent/?limit=20

Returns recently active assets, analyses, and figures (limit default 20, max 1000).

POST /api/{version}/workspace/{api_id}/promotion/

Request Body:

{ "promotion_code": "string" }

Applies a promotion code and returns the resulting plan. Requires MANAGE.

GET /api/{version}/workspace/{api_id}/members/
POST /api/{version}/workspace/{api_id}/members/add/
POST /api/{version}/workspace/{api_id}/members/remove/
POST /api/{version}/workspace/{api_id}/members/change/
GET /api/{version}/workspace/{api_id}/subscription/
POST /api/{version}/workspace/{api_id}/subscription/
GET /api/{version}/workspace/{api_id}/storage/
POST /api/{version}/workspace/{api_id}/storage/
POST /api/{version}/workspace/{api_id}/storage/test/

Manage the workspace plan and custom storage. Workspaces governed by an organization-level subscription return 409 with managed_by_organization: true.

GET /api/{version}/workspace/{api_id}/compute_instances/
POST /api/{version}/workspace/{api_id}/compute_instances/
GET /api/{version}/workspace/{api_id}/compute_instances/launch_options/
GET /api/{version}/workspace/{api_id}/compute_allowance/
GET /api/{version}/workspace/{api_id}/compute_usage/

List and launch managed-compute instances in the workspace. See Managed Compute for the instance lifecycle and POST body. (v1.4.1+)


An analysis is a container for figures within a workspace.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, name, description, workspace (api_id), figures (read-only), assets (read-only), thumbnail (read-only), size_bytes, is_imported, import_source, import_source_asset, plus common fields.

POST /api/{version}/analysis/

Request Body:

{
"name": "string",
"description": "string",
"workspace": "uuid"
}

A figure is a named slot within an analysis; its content lives in figure revisions.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, name, description, analysis (api_id), revisions (read-only, shallow), thumbnail (read-only), size_bytes, auto_assign_pending, is_imported, import_source, import_source_asset, plus common fields.

POST /api/{version}/figure/

Request Body:

{
"name": "string",
"description": "string",
"analysis": "uuid"
}

A figure revision is an immutable snapshot of a figure’s image, code, and data.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, short_id, figure (api_id), metadata (JSON), revision_index (read-only), data (read-only; shallow in v1.2+), assets (read-only links), thumbnail, figure_metadata (read-only context object), image_hash, size_bytes, is_processing, is_clean_room, description, description_timestamp, description_author, is_imported, import_source, import_source_asset, plus common fields. client_id (UUID) is write-only and sets the revision’s primary key (v1.4.1+).

POST /api/{version}/revision/

Request Body:

{
"figure": "uuid",
"metadata": {...},
"short_id": "string", // optional; prefix must be reserved by the user
"is_clean_room": false,
"data": [ // ExternalData objects (base64 data)
{ "name": "string", "type": "image", "metadata": {...}, "data": "base64" }
]
}

Data is processed asynchronously — poll the status action.

GET /api/{version}/revision/{api_id}/status/

Response:

{ "is_processing": false }
GET /api/{version}/revision/{api_id}/comment_count/

Returns the number of top-level comments: { "count": int }.

POST /api/{version}/revision/{api_id}/generate_description/

Generates an AI description for the revision and stores it (author set to the ai system user). Requires AI to be enabled. Returns the updated revision.

POST /api/{version}/revision/{api_id}/derive/

Creates a new revision by cloning the source revision’s data objects (same storage paths), returning the new revision immediately with its api_id so a watermark can be generated before uploading image data via append_data.

Request Body (all optional):

{
"figure": "uuid", // target figure; defaults to the source's figure
"metadata": {...}
}
POST /api/{version}/revision/{api_id}/append_data/

Appends data objects to an existing revision without deleting existing data (used after derive to upload watermarked images, code, and manifests).

Request Body:

{ "data": [ /* ExternalData objects with base64 data */ ] }
POST /api/{version}/revision/auto-assign/

Creates a revision under a temporary figure and dispatches AI tasks to assign it to the most appropriate figure in the analysis.

Request Body:

{
"analysis": "uuid",
"metadata": {...},
"data": [ /* ExternalData objects */ ]
}

Assets are reusable data objects (datasets, tables, files) that can be linked to figures.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, name, description, workspace (api_id), analysis (api_id, optional), revisions (read-only, shallow), thumbnail, size_bytes, plus common fields.

POST /api/{version}/asset/

Request Body:

{
"name": "string",
"description": "string",
"workspace": "uuid",
"analysis": "uuid" // optional
}
POST /api/{version}/asset/find_by_name/

Finds assets by exact name, optionally scoped to an analysis.

Request Body:

{
"name": "string",
"analysis": "uuid" // optional
}

Response: 200 OK — JSON array of matching assets the user can view.


An asset revision is an immutable snapshot of an asset’s data.

Supports the standard CRUD routes and common sub-actions.

Response fields: api_id, asset (api_id), metadata (JSON), data (read-only, shallow), revision_index, thumbnail, data_hash, figure_revisions (read-only links), size_bytes, is_processing, plus common fields. client_id (UUID) is write-only.

POST /api/{version}/asset_revision/

Request Body:

{
"asset": "uuid",
"metadata": {...},
"data": [ /* ExternalData objects with base64 data */ ]
}
GET /api/{version}/asset_revision/{api_id}/status/

Response: { "is_processing": false }

POST /api/{version}/asset_revision/find_by_hash/

Finds asset revisions by content hash. Used for deduplication during sync.

Request Body:

{
"hash_type": "blake3",
"digest": "string",
"analysis": "uuid" // Optional
}
  • hash_type (required): Hash algorithm. Currently only blake3 is supported.
  • digest (required): The hex-encoded content hash.
  • analysis (optional): API ID of an analysis. When provided, only revisions whose parent asset belongs to that analysis are returned. When omitted, returns all matching revisions workspace-wide, including both scoped and unscoped assets. Note: omitting analysis does not filter to unscoped-only assets.

Response: 200 OK — JSON array of matching asset revision objects, or an empty array if none found.

Python Client: AssetRevision.find_by_hash(digest, hash_type="blake3", analysis=None) R Client: find_asset_revision_by_hash(gf, digest, hash_type="blake3")

POST /api/{version}/asset_revision/{api_id}/unlink_figure/

Unlinks a figure revision from an asset revision.

Request Body:

{
"figure_revision": "uuid",
"anchor": "string", // Optional
"delete_figure_revision": false // Optional
}

Read-only access to the individual data objects (images, code, tables, manifests) attached to figure and asset revisions. Data objects are created and updated through their parent revision, not directly — POST, PUT, PATCH, and DELETE on this resource return 405 Method Not Allowed.

GET /api/{version}/data/{api_id}/

Response fields: api_id, name, type, metadata (JSON), data (base64; null when shallow), size_bytes, hash, is_clean_room.

GET /api/{version}/data/{api_id}/storage/

Returns the storage backend vendor, hash, and (for admins or third-party storage) the path of the underlying object. Requires MANAGE on the workspace.


Stories are AI-generated presentations from figure collections.

GET /api/{version}/story/

GET /api/{version}/story/{api_id}/

Response:

{
"api_id": "uuid",
"name": "string",
"description": "string",
"workspace": "uuid",
"revisions": [...],
"slides": [...],
"created_on": "datetime",
"updated_on": "datetime"
}

POST /api/{version}/story/

Request Body:

{
"name": "string",
"description": "string",
"workspace": "uuid",
"revisions": ["uuid", "uuid", ...], // Figure revision IDs
"generate": false // Optional; if true, dispatch AI generation
}

When generate is true, the story is created and an asynchronous generation task is dispatched; the response story carries a generation_status of generating (poll via the Tasks API).


PUT /api/{version}/story/{api_id}/
PATCH /api/{version}/story/{api_id}/

Request Body:

{
"name": "string",
"description": "string",
"revisions": ["uuid", ...], // Replaces all revisions
"slides": [ // Replaces all slides
{
"slide_id": "string",
"slide_type": "title|introduction|figure|goals|data|conclusion|custom",
"position": 0,
"content": "string",
"revision_id": "uuid", // For figure slides
"slide_data": {...}
}
]
}

For figure slides, server-owned AI fields (methods, data, availability) are preserved if omitted from the client payload.


DELETE /api/{version}/story/{api_id}/

Comments support Markdown, @mentions, and threading.

GET /api/{version}/comment/?target_type={type}&target_id={uuid}

Query Parameters (required):

  • target_type: asset, asset_revision, figure, or figure_revision
  • target_id: API ID of the target object

Response: 200 OK

[
{
"id": "uuid",
"user": {...},
"content": "string",
"parent_comment_id": "uuid|null",
"is_edited": false,
"created_on": "datetime",
"updated_on": "datetime"
}
]

POST /api/{version}/comment/

Request Body:

{
"target_type": "figure_revision",
"target_id": "uuid",
"content": "Great analysis! @username what do you think?",
"parent_comment_id": "uuid" // Optional, for replies
}

Mentions using @username trigger email notifications.


PUT /api/{version}/comment/{id}/

Only the comment author can edit. Sets is_edited: true.

Request Body:

{
"content": "Updated comment text"
}

DELETE /api/{version}/comment/{id}/

Only the comment author can delete.


POST /api/{version}/comment/{parent_id}/create_ai_response/

Creates an AI-authored reply to the specified comment. The AI generates the response asynchronously.

Response: 201 Created - The empty AI comment (content populated async)


Emoji reactions on comments.

GET /api/{version}/reaction/?comment_id={uuid}

POST /api/{version}/reaction/

Request Body:

{
"comment_id": "uuid",
"emoji": "👍"
}

DELETE /api/{version}/reaction/{id}/

AI-powered analysis of figures using Amazon Bedrock. All Deep Insight endpoints require AI to be enabled on the site (503 otherwise) and are subject to plan-based rate limiting and token quotas (429 when exhausted).

POST /api/{version}/deep_insight/

Request Body:

{
"figure_revision": "uuid",
"prompt": "Explain this figure",
"stream": false,
"model": "us.amazon.nova-pro-v2:0" // Optional
}

Response (non-streaming):

{
"response": "string"
}

Response (streaming): Server-Sent Events


POST /api/{version}/deep_insight/compare/

Request Body:

{
"left_revision": "uuid",
"right_revision": "uuid",
"stream": true
}

POST /api/{version}/deep_insight/figure_code/

Extracts the code that generated a figure using AI.

Request Body:

{
"figure_revision": "uuid"
}

Response:

{
"code": "string"
}

POST /api/{version}/deep_insight/code_edit/

Agentic AI editing of a clean-room figure’s code. Accepts a conversation and returns the assistant’s reply along with revised, validated code.

Request Body:

{
"figure_revision": "uuid",
"messages": [ {...} ],
"current_code": "string",
"figure_image": "data:image/png;base64,...", // optional
"available_packages": ["numpy", "pandas"], // optional
"model": "string" // optional
}

Response:

{
"role": "assistant",
"content": "string",
"code": "string",
"valid": true,
"error": null,
"tool_calls": [...]
}

POST /api/{version}/deep_insight/datasets/

Returns data inputs/outputs for a figure revision.

Response:

{
"external_data": [...],
"ai_inputs": [...],
"ai_outputs": [...]
}

POST /api/{version}/deep_insight/text_only/

AI query without a figure (text-only context).

Request Body:

{
"text": "string",
"prompt": "string"
}

POST /api/{version}/deep_insight/check/

Checks if AI can process a figure (permissions, rate limits).

Response:

{
"available": true,
"messages": []
}

Optimized AI endpoints used to build and refine stories.

POST /api/{version}/deep_insight/story/figure/
POST /api/{version}/deep_insight/story/overviews/
POST /api/{version}/deep_insight/story/refine/

Synchronous helpers that generate per-figure content, story overviews, and refinements.

POST /api/{version}/deep_insight/story/slide/generate/

Request Body:

{
"story_id": "uuid",
"slide_type": "introduction|goals|data|conclusion|figure|...",
"revision_id": "uuid", // required for figure slides
"model": "string" // optional
}

Response (figure slide): { "content", "methods", "inputs", "outputs" } Response (overview slide): { "content", "figure_descriptions", "figure_methods" }

POST /api/{version}/deep_insight/story/slide/detail/

Rewrites a slide with more or less detail.

Request Body:

{
"story_id": "uuid",
"slide_id": "string",
"direction": "more", // "more" | "less"
"current_content": "string",
"model": "string" // optional
}

Response: { "content": "string" }

POST /api/{version}/deep_insight/story/generate/

Submits asynchronous generation of an entire story. Cancels any in-flight generation and sets the story’s generation_status to generating.

Request Body: { "story_id": "uuid" } Response: { "task_id": "uuid" } — poll via the Tasks API.

POST /api/{version}/deep_insight/story/refine_async/

Submits asynchronous refinement of a story (generation_status becomes refining).

Request Body: { "story_id": "uuid" } Response: { "task_id": "uuid" }


POST /api/{version}/search/

Unified search across workspaces, analyses, figures, figure revisions, assets, and asset revisions. Results are filtered by per-object permissions.

Request Body:

{
"search_type": "keyword", // "keyword" | "text" | "semantic" | "image"
"query": "string", // for keyword/text/semantic
"keywords": ["string"], // alternative to query (joined)
"image": "base64", // required for image search
"k": 10, // optional max results (default 10)
"workspace": "uuid" // optional; restrict to one workspace
}
  • keyword / text — full-text search across all indexed entity types, with highlight snippets.
  • semantic — cross-modal (Nova/Bedrock) k-NN search over figure revisions; requires query.
  • image — reverse-image search; requires a base64-encoded image.

Response: 200 OK — array sorted by descending score:

[
{
"score": 0.87,
"object": {...}, // shallow-serialized matching entity
"highlight": {...} // per-field match snippets (keyword only)
}
]

Returns 400 on a missing or unsupported search_type, or a missing query.


Cloud notebook/IDE instances managed by GoFigr. (Available in v1.4.1+.) Instances are listed and launched through their workspace, then operated through the compute/instance/ routes.

GET /api/{version}/workspace/{api_id}/compute_instances/
POST /api/{version}/workspace/{api_id}/compute_instances/
GET /api/{version}/workspace/{api_id}/compute_instances/launch_options/
GET /api/{version}/workspace/{api_id}/compute_allowance/
GET /api/{version}/workspace/{api_id}/compute_usage/?period=YYYY-MM

Launch Request Body:

{
"name": "string", // required
"tier": "string", // optional tier id
"data_volume_gb": 50 // optional
}

launch_options/ returns the available tiers and limits; compute_allowance/ and compute_usage/ report remaining allowance and billable usage.

GET /api/{version}/compute/instance/{api_id}/
PATCH /api/{version}/compute/instance/{api_id}/
POST /api/{version}/compute/instance/{api_id}/start/
POST /api/{version}/compute/instance/{api_id}/stop/
POST /api/{version}/compute/instance/{api_id}/terminate/
POST /api/{version}/compute/instance/{api_id}/change-tier/
GET /api/{version}/compute/instance/{api_id}/connect/
GET /api/{version}/compute/instance/{api_id}/heartbeat/
GET /api/{version}/compute/instance/{api_id}/events/
GET /api/{version}/compute/instance/{api_id}/usage/?period=YYYY-MM
  • PATCH updates name, idle_shutdown_enabled, and idle_shutdown_seconds.
  • start / stop / terminate drive the lifecycle (202 Accepted). start may return 402 allowance_exhausted or 409 tier_unavailable.
  • change-tier — body { "tier": "string" }; the instance must be stopped (409 otherwise).
  • connect — body-less GET (so a browser can navigate directly). Query app (default jupyter). Returns { "redirect_url", "expires_in_seconds" } with a short-lived signed URL. Owner only.
  • heartbeat (GET) — latest supervisor status: { "heartbeat_at", "heartbeat": { "jupyter_up", "active_kernel_count", "cpu_pct", "mem_pct", "disk_pct", ... } }.

A 404 is returned for both nonexistent and inaccessible instances.

Instance fields (selected): api_id, name, tier, workspace, owner, user_facing_status, lifecycle, health, status_detail, last_activity_at, running_since, idle_shutdown_enabled, idle_shutdown_seconds, idle_seconds, can_operate, can_connect, can_terminate, created_at, updated_at.

GET /api/{version}/compute/tiers/

Lists the public compute-tier catalog (label, vCPU, memory, description).


Background task tracking for user-initiated asynchronous work (story generation, imports, etc.). (Available in v1.3+.) Read-only; scoped to the authenticated user’s own tasks.

GET /api/{version}/tasks/

Query Parameters: status__in, created_at__gte, created_at__lte, completed_at__gte, completed_at__lte.

GET /api/{version}/tasks/{task_id}/

Response fields: task_id, task_name, task_type, status, progress, status_message, task_detail, result, error, created_on, started_on, completed_on. Cancelled tasks report status REVOKED.

GET /api/{version}/tasks/{task_id}/logs/

Response: { "task_id": "uuid", "logs": [...] }

POST /api/{version}/tasks/{task_id}/cancel/

Revokes the task in Celery and marks it cancelled. Returns 400 if the task already succeeded, failed, or was revoked.


Users are addressed by username (not UUID).

Response fields: username, email, first_name, last_name, date_joined, is_active, is_staff, avatar, email_confirmed, using_auth0, user_profile. Sensitive fields (email, user_profile, email_confirmed, is_active, is_staff) are stripped when viewing a user other than yourself.

GET /api/{version}/user/?q={query}
GET /api/{version}/user/{username}/
POST /api/{version}/user/

Request Body:

{
"username": "string",
"email": "string",
"password": "string",
"first_name": "string",
"last_name": "string"
}

Response: 201 Created — the created user plus an auth object containing JWT tokens.

PUT /api/{version}/user/{username}/
PATCH /api/{version}/user/{username}/

Self only. Accepts email, first_name, last_name, password, avatar, and a nested user_profile payload.

GET /api/{version}/user/{username}/contributions/

Returns the authenticated user’s activity counts per date over the last 365 days.

POST /api/{version}/user/{username}/verify_email/

With a token in the body, confirms the user’s email. Without a token, generates and emails a new verification token.


GET /api/{version}/plan/

Lists available subscription plans (read-only).

Response fields: api_id, name, description, monthly_cost, annual_cost, max_storage_bytes, max_users, allow_flexible_storage, monthly_token_quota, deep_insight_rate, compute_enabled, compute_max_running_instances, idle_shutdown_required, max_idle_seconds, default_idle_seconds, effective_max_data_volume_gb.


Programmatic access tokens (used by the Python and R clients). For security, API keys can only be created or deleted with username/password (JWT) authentication — not while authenticated with an API key.

GET /api/{version}/api_key/

Response: array of { "api_id", "name", "token": null, "expiry", "last_used", "created", "workspace" }. The secret token is never returned on list/retrieve.

GET /api/{version}/api_key/{api_id}/
POST /api/{version}/api_key/

Request Body:

{
"name": "string", // required, unique per user
"workspace": "uuid", // optional; scopes the key to one workspace
"expiry": "datetime" // optional; must be in the future
}

Response: 201 Created

{
"api_id": "uuid",
"name": "string",
"token": "string", // the secret — returned ONLY on create
"expiry": "datetime",
"last_used": null,
"created": "datetime",
"workspace": "uuid",
"user": "string"
}
DELETE /api/{version}/api_key/{api_id}/

Manage SSH keys for Git repository imports.

GET /api/{version}/ssh_key/

Response:

[
{
"api_id": "uuid",
"name": "string",
"fingerprint": "SHA256:...",
"is_default": true,
"created_on": "datetime"
}
]

POST /api/{version}/ssh_key/

Request Body:

{
"name": "My Git Key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----...",
"is_default": false
}

Note: Private key is stored encrypted. Never returned in API responses.


PATCH /api/{version}/ssh_key/{api_id}/

Request Body:

{
"name": "New Name",
"is_default": true
}

DELETE /api/{version}/ssh_key/{api_id}/

POST /api/{version}/git/check/

Validates Git repository URL and authentication.

Request Body:

{
"url": "https://github.com/user/repo.git",
"ssh_key_id": "uuid" // Optional, for SSH URLs
}

POST /api/{version}/user_data_upload/

Upload and process files (Git repos, PowerPoint, Word docs).


Invite users to a workspace or organization. The same routes exist for both targets — substitute workspace or organization for {target}.

POST /api/{version}/invitations/{target}/

Requires MANAGE on the target. An email is sent to the recipient.

Request Body:

{
"workspace": "uuid", // or "organization": "uuid"
"email": "string",
"membership_type": "string",
"expiry": "datetime" // optional; capped to a maximum TTL
}

Response: 201 Created — the serialized invitation. The token field is only populated in debug builds.

GET /api/{version}/invitations/{target}/{token}

Looks up an invitation by its token (any valid invite) or by api_id (requires MANAGE). Returns 404 if expired or not found.

POST /api/{version}/invitations/{target}/{token}/accept

Adds the requesting user to the target with the invitation’s membership type and consumes the invite.

Response: 200 OK{ "message": "Invitation accepted successfully" }. Returns 400 if the collaborator limit has been reached.

DELETE /api/{version}/invitations/{target}/{api_id}

Revokes a pending invitation (the path segment must be the invitation’s api_id). Requires MANAGE.


Stripe-backed subscription management. Every request targets exactly one of workspace_api_id or organization_api_id; the caller needs MANAGE on the target. Organization-managed workspaces are rejected with 409 and managed_by_organization: true.

POST /api/{version}/billing/checkout/

Starts a Stripe Checkout session for a new paid subscription.

Request Body:

{
"plan_api_id": "uuid",
"frequency": "monthly", // or "annual"
"workspace_api_id": "uuid" // or "organization_api_id"
}

Response: 200 OK{ "checkout_url", "session_id" }. Returns 409 if an active subscription already exists (use change-plan).

POST /api/{version}/billing/portal/

Returns a Stripe Customer Portal URL.

Request Body:

{ "workspace_api_id": "uuid" } // or "organization_api_id"

Response: 200 OK{ "portal_url" }. Returns 409 if there is no Stripe customer yet.

POST /api/{version}/billing/change-plan/

Switches an existing paid subscription to a different plan or billing frequency (with proration).

Request Body:

{
"plan_api_id": "uuid",
"frequency": "annual",
"workspace_api_id": "uuid" // or "organization_api_id"
}

Response: 200 OK{ "subscription_id", "plan_api_id", "frequency", "message" }.


Endpoints for accounts managed via Auth0. All return 503 when Auth0 is not configured.

POST /api/{version}/auth0/resend-verification/

Resends the email-verification message for the bearer-token user. Response: { "detail": "Verification email sent" }.

POST /api/{version}/auth0/change-password/

Returns a password-change ticket URL. Body (optional): { "return_url": "string" }. Response: { "url": "string" }.

GET /api/{version}/auth0/mfa-status/

Response: { "enrolled": true, "methods": ["..."] }.

POST /api/{version}/auth0/mfa-enroll/

Returns a Guardian enrollment ticket URL. Response: { "url": "string" }.


Short IDs are compact, shareable identifiers for figure revisions. Clients reserve a unique prefix, then append a locally generated base62 index.

POST /api/{version}/short_id_prefix/reserve

Reserves a unique short-ID prefix for the authenticated user.

Response: 201 Created{ "prefix": "string" }.

GET /api/{version}/resolve/{short_id}

Resolves a short ID to a figure revision. No authentication is required, but the revision’s VIEW permission is still enforced.

Response: 200 OK{ "api_id": "uuid", "short_id": "string" }. Returns 404 for both nonexistent and inaccessible revisions (to avoid leaking which short IDs are valid).


GET /api/{version}/ai/usage/

Returns AI usage statistics and quota information.


Short-lived secret tokens that let a running notebook/Jupyter host push figure metadata to GoFigr regardless of origin (open CORS, secured by a ≤60-second token). Used by real-time capture integrations.

POST /api/{version}/metadata/

Creates a token (requires authentication). Optional expiry (capped to a maximum TTL). Response: 201 Created — the serialized token including its secret token value.

GET /api/{version}/metadata/{token}

Returns the token object. Only the user who created it may read it.

POST /api/{version}/metadata/{token}

Stores metadata against the token.

Request Body: { "metadata": {...} }


Version Key Changes
v1.4.1 Managed compute API, client-provided revision IDs (client_id), shallow create responses for revisions
v1.4 AI-generated titles and descriptions (ai_title, ai_description fields)
v1.3 Tasks API, Comments, Reactions, created_on_behalf fields, optimized workspace list
v1.2 Lazy-loaded revision data (data returned separately, not inline)
v1.1 Nested objects in responses (analyses/figures return full objects, not just IDs)
v1 Original API
  • Managed Compute: Cloud notebook/IDE instances (/compute/instance/, workspace launch routes)
  • Client-provided IDs: Revisions accept a write-only client_id to set their primary key
  • Shallow create responses: Figure/asset revision creation returns a lightweight representation
  • Added ai_title and ai_description fields to figures and revisions
  • AI-generated descriptions for imported content
  • Tasks API: Background task tracking (/tasks/ endpoint)
  • Comments & Reactions: Full collaboration features
  • Attribution: created_on_behalf, created_on_behalf_name, created_on_behalf_email fields
  • Performance: ShallowWorkspaceSerializer for list operations
  • Revision data: Data objects returned via separate fetch, not inline with revision
  • Improves performance for large revisions
  • Nested objects: Workspace responses include full analysis objects (not just IDs)
  • Analysis responses include full figure objects
  • Original API with core CRUD operations

  1. API Versioning: Use v1.4.1 for new integrations.
  2. Data Processing: Revisions are processed asynchronously. Check the status endpoint.
  3. Shallow Representations: List endpoints and v1.2+ revision data return lightweight objects; fetch full data separately.
  4. Silent Operations: Use ?silent=true to mark an operation’s activity entry as silent — it is still recorded but hidden from most activity views.
  5. Base64 Encoding: Binary data (images, files) is base64-encoded.
  6. Rate Limiting: AI endpoints are rate-limited based on plan.

Last Updated: June 2026
API Versions Supported: v1, v1.1, v1.2, v1.3, v1.4, v1.4.1