Skip to Content
DocsAPI ReferenceREST API

REST API Reference

Base URL: https://app.marqov.ai (production) or http://localhost:3000 (development)

All authenticated endpoints require a Supabase session cookie. Responses are JSON. Errors return { "error": "message" }.


Authentication

POST /api/auth/validate-code

Validate an invitation code for platform access. Public endpoint — no authentication required.

Rate limit: 5 requests/minute per IP.

FieldTypeRequiredDescription
codestringYesInvitation code (1-64 chars, alphanumeric + hyphens/underscores)

Response (200):

FieldTypeDescription
validbooleanWhether the code is valid
remaining_usesnumberNumber of remaining uses for this code

Error codes: 400 (invalid code), 429 (rate limited), 500 (server error).


Jobs

POST /api/jobs/submit

Submit a quantum job for execution. Requires authentication.

Rate limits:

  • User: 10 requests/minute
  • Team daily quota: 100 jobs/day

Request body:

FieldTypeRequiredDescription
script_idUUIDOne of script_id, script_slug, or inline_codeScript UUID
script_slugstringSee aboveScript slug (e.g., bell-state)
inline_codestringSee aboveRaw code to execute (max 50,000 chars)
frameworkstringNoqiskit, cirq, pennylane, openqasm, or marqov
backendstringYesBackend slug (see GET /api/backends)
paramsobjectYesExecution parameters (see below)
params.shotsintegerYesNumber of measurement shots (1-100,000)
params.thetanumberNoVQE rotation angle
params.graph_sizeintegerNoQAOA graph size (2-20)
params.layersintegerNoQAOA layers (1-10)
params.noise_modelobjectNoNoise model for noisy backends
create_capsulebooleanNoCreate a reproducibility capsule (default: false)
capsule_namestringNoName for the capsule (1-200 chars)
execution_modestringNodirect or temporal (default: direct)

Response (200):

FieldTypeDescription
job_idUUIDCreated job run identifier

Error codes: 400 (validation), 401 (unauthorized), 402 (budget exceeded), 404 (script not found), 429 (rate limited), 500 (server error).

402 response includes:

FieldTypeDescription
errorstringReason for budget rejection
estimated_costnumberEstimated cost in USD
current_spendnumberCurrent team spend
budgetnumberTeam budget limit
remaining_budgetnumberRemaining budget

Playground

POST /api/playground/run

Execute code in the playground. Requires authentication.

Rate limit: 10 requests/minute (shared with job submission).

Request body:

FieldTypeRequiredDescription
codestringYesSource code (1-100,000 chars)
languagestringYesauto, qiskit, cirq, pennylane, openqasm, or marqov
backendstringYesBackend slug
shotsintegerYesNumber of shots (1-100,000)

Response (200):

FieldTypeDescription
countsobjectMeasurement outcome counts (e.g., {"00": 512, "11": 488})
backendstringBackend used
shotsintegerShots executed
execution_time_msnumberExecution time in milliseconds
cost_usdnumberCost (currently always 0.0 for playground)
language_detectedstringResolved language
circuit_infoobjectCircuit metadata from worker

Error codes: 400 (validation), 401 (unauthorized), 422 (language detection failed or worker error), 429 (rate limited), 502 (worker unreachable), 503 (worker not configured).

POST /api/playground/convert

Convert Python quantum code to OpenQASM without simulation. Requires authentication.

Rate limit: 10 requests/minute (shared with job submission).

Request body:

FieldTypeRequiredDescription
codestringYesPython source code (1-100,000 chars)
languagestringYesqiskit, cirq, pennylane, or marqov

Response (200):

FieldTypeDescription
qasmstringOpenQASM output
circuit_infoobjectCircuit metadata

Error codes: 400, 401, 422, 429, 502, 503.

POST /api/playground/telemetry

Record browser simulation telemetry events. Requires authentication.

Request body:

FieldTypeRequiredDescription
session_idstringYesClient session identifier
team_idUUIDYesTeam ID
simulatorstringYesquantum-circuit or qulacs-wasm
qasm_inputstringYesQASM input (max 100,000 chars)
shotsintegerYesShots (1-100,000)
qubit_countintegerYesQubit count (1-50)
gate_countintegerYesGate count (0-10,000)
execution_time_msnumberYesClient-side execution time
countsobjectYesMeasurement counts
source_frameworkstringNoqiskit, cirq, pennylane, or qasm
user_agentstringNoBrowser user agent (max 500 chars)

Response (201): { "success": true }


Backends

GET /api/backends

List all available quantum backends with pricing and metadata. Public endpoint — no authentication required.

Cache: CDN 5 min (s-maxage=300), client 10 min (max-age=600), stale-while-revalidate 1 hour.

Response (200):

FieldTypeDescription
backendsBackend[]Array of available backends
updatedAtstringISO 8601 timestamp

Backend object:

FieldTypeDescription
idUUIDBackend ID
slugstringURL-friendly identifier (e.g., sv1)
namestringDisplay name
providerstringProvider name (e.g., AWS Braket)
deviceTypestringsimulator or qpu
providerTargetIdstringProvider device ARN or target ID
regionstring|nullAWS region
qubitCountinteger|nullNumber of qubits
topologystring|nullQubit connectivity topology
isAvailableboolean|nullCurrent availability
statusstringonline, offline, or maintenance
pricingobject{ taskFee, perShot, minimumCost }
maxShotsinteger|nullMaximum shots per task
maxQubitsinteger|nullMaximum qubits
descriptionstring|nullHuman-readable description
documentationUrlstring|nullLink to provider docs
tagsstring[]|nullSearchable tags
displayOrderinteger|nullSort order
isRecommendedboolean|nullFeatured backend

Scripts

GET /api/scripts

List scripts accessible to the current user. Requires authentication.

Query parameters:

ParamTypeDefaultDescription
limitinteger50Max results (max 100)
offsetinteger0Pagination offset
script_typestringFilter by workflow or task
user_onlybooleanfalseOnly show user’s own scripts

Response (200):

FieldTypeDescription
scriptsobject[]Script list (without script_content)
totalintegerTotal count for pagination
limitintegerApplied limit
offsetintegerApplied offset

Script list item:

FieldTypeDescription
idUUIDScript ID
namestringScript name
descriptionstringDescription
script_typestringworkflow or task
categorystringScript category
is_publicbooleanWhether script is published
is_hardcodedbooleanWhether script is a platform template
created_atstringISO 8601 timestamp
executions_countintegerNumber of executions

GET /api/scripts/:id

Get full details of a specific script, including content and recent executions. Requires authentication.

Response (200): Full script object plus executions array (last 10).

POST /api/scripts

Save a completed job’s inline code as a reusable script. Requires authentication.

Request body:

FieldTypeRequiredDescription
job_idUUIDYesCompleted job ID
namestringYesScript name (1-200 chars)
descriptionstringYesDescription (1-2,000 chars)
slugstringYesURL-friendly slug (lowercase, numbers, hyphens)

Response (201): { "script_id": "uuid" }

Error codes: 400 (no inline code, not completed), 401, 403 (not owner), 404 (job not found), 409 (slug conflict).

POST /api/scripts/upload

Upload a new Python script with optional pip dependencies. Requires authentication.

Rate limit: 5 uploads/minute.

Request body:

FieldTypeRequiredDescription
namestringYesScript name (1-200 chars)
descriptionstringNoDescription (max 1,000 chars)
script_contentstringYesPython source code
requirementsstringNorequirements.txt content
script_typestringNoworkflow or task (auto-detected if omitted)

Response (200):

FieldTypeDescription
script_idUUIDCreated script ID
namestringScript name
script_typestringDetected or specified type
statusstringvalidated
validation_warningsstring[]Warnings from validation (if any)
metadataobjectScript metadata from AST analysis

PATCH /api/scripts/:id

Update a script’s metadata and/or code. Only for unpublished scripts owned by the user.

Request body (at least one field required):

FieldTypeDescription
namestringNew name
descriptionstringNew description
script_contentstringUpdated Python source code (validated)
requirementsstringUpdated requirements.txt (validated)
frameworkstringFramework (qiskit, cirq, pennylane, openqasm, marqov)

Error codes: 400 (validation failed, public script), 401, 403 (not owner), 404.

DELETE /api/scripts/:id

Soft-delete a script (sets is_active = false). Only for unpublished scripts owned by the user.

Error codes: 400 (public script), 401, 403 (not owner), 404.


Capsules

POST /api/capsules/create

Create a new capsule in draft state. Requires authentication.

Rate limit: 5 capsules/minute.

Request body:

FieldTypeRequiredDescription
namestringYesCapsule name (1-200 chars)
descriptionstringNoDescription (max 1,000 chars)
tagsstring[]NoUp to 10 tags (max 50 chars each)
workflowobjectNoWorkflow definition with tasks array
workflow.tasks[].namestringYesTask name
workflow.tasks[].script_idUUIDYesScript ID
workflow.tasks[].backendstringYesBackend slug
workflow.tasks[].parametersobjectYesTask parameters
backendsstring[]NoBackend slugs
max_budget_usdnumberNoMaximum budget (0-500)
retention_yearsintegerNoData retention period (1-100)
regulatory_frameworkstringNoe.g., FDA-21CFR11

Response (201): { "capsule_id": "uuid" }

GET /api/capsules/:id

Fetch a single capsule by ID. Requires authentication (team-scoped via RLS).

PATCH /api/capsules/:id

Update a draft capsule. Only draft capsules can be modified. Owner only.

Request body: Same fields as create (all optional, at least one required).

Error codes: 400, 401, 403 (not draft or not owner), 404.

DELETE /api/capsules/:id

Delete a capsule. Cannot delete sealed or archived capsules. Owner only.

Error codes: 401, 403 (sealed/archived or not owner), 404.

POST /api/capsules/:id/seal

Seal a capsule, making it immutable.

POST /api/capsules/:id/run

Run a capsule in verify or template mode.

POST /api/capsules/:id/clone

Clone a capsule.

POST /api/capsules/:id/archive

Archive a sealed capsule.

POST /api/capsules/:id/publish

Publish a sealed capsule.

GET /api/capsules/:id/export

Export a capsule as a downloadable package.

POST /api/capsules/from-job

Create a capsule from an existing completed job.

POST /api/capsules/upload

Upload a capsule from a YAML definition file.

POST /api/capsules/import

Import a capsule package.


Team

GET /api/team/members

List all members of the authenticated user’s team. Requires authentication.

Query parameters:

ParamTypeDefaultDescription
team_idUUIDUser’s first teamTeam to list members for

Response (200):

FieldTypeDescription
team_idUUIDTeam ID
membersobject[]Array of member objects
members[].user_idUUIDMember user ID
members[].emailstringMember email
members[].namestringDisplay name or email prefix
members[].rolestringowner, admin, or member
members[].joined_atstringISO 8601 timestamp

PATCH /api/team/members/:userId

Update a team member’s role. Admin/owner only.

Rate limit: 30 requests/minute.

Request body:

FieldTypeRequiredDescription
team_idstringYesTeam ID
rolestringYesadmin or member (cannot assign owner)

Error codes: 400, 401, 403 (not admin/owner, cannot change owner), 404, 429.

DELETE /api/team/members/:userId

Remove a member from the team. Admin/owner only. Cannot remove self or owner.

Rate limit: 30 requests/minute.

Request body: { "team_id": "uuid" }

GET /api/team/invitations

List pending invitations for the user’s team. Requires authentication.

Query parameters: team_id (optional).

POST /api/team/invitations

Create a team invitation. Admin/owner only.

Rate limit: 10 requests/minute.

Request body:

FieldTypeRequiredDescription
team_idstringYesTeam ID
emailstringYesInvitee email
rolestringYesadmin or member
messagestringNoOptional message (max 500 chars)

Response (201): Invitation object with id, email, role, expires_at.

Error codes: 400 (already member, pending invite), 401, 403 (not admin/owner, suspended), 429.

DELETE /api/team/invitations/:id

Cancel a pending invitation.

GET /api/team/secrets

List all secrets for the user’s teams. Values are always masked ("value": "......"). Requires authentication.

POST /api/team/secrets

Create or update provider credentials. Admin/owner only.

Rate limit: 20 requests/minute.

Request body:

FieldTypeRequiredDescription
team_idstringYesTeam ID
providerstringYesProvider name (e.g., aws, azure)
secretsobjectYesKey-value pairs of secret names and values

Error codes: 400 (invalid provider, missing fields), 401, 403 (not admin/owner, suspended), 429.

DELETE /api/team/secrets/:id

Delete a specific secret. Admin/owner only.

POST /api/team/secrets/test

Test a secret connection (validate credentials).

GET /api/team/usage

Get team usage and spend data for the current or specified month. Requires authentication.

Query parameters: month (optional, format: YYYY-MM).

Response (200):

FieldTypeDescription
periodobject{ start, end, month }
summaryobject{ totalSpend, lastMonthSpend, changePercent }
byProviderobject[]Spend grouped by provider
byBackendobject[]Spend grouped by backend
dailyobject[]Daily spend for charting

Profile

PATCH /api/profile

Update user profile. Requires authentication.

Rate limit: 30 requests/minute.

Request body (all fields optional):

FieldTypeConstraints
usernamestring3-30 chars, alphanumeric + hyphens/underscores
display_namestring|nullMax 100 chars
biostring|nullMax 500 chars
avatar_urlstring|nullMax 500 chars
websitestring|nullMax 200 chars
locationstring|nullMax 100 chars
github_usernamestring|nullMax 39 chars
twitter_usernamestring|nullMax 15 chars
linkedin_urlstring|nullMax 200 chars
is_publicbooleanProfile visibility

Error codes: 400 (username taken), 401, 429.


Rate Limits Summary

EndpointLimitScope
POST /api/jobs/submit10/minPer user
POST /api/jobs/submit100/dayPer team
POST /api/playground/run10/minPer user (shared with job submit)
POST /api/playground/convert10/minPer user (shared)
POST /api/capsules/create5/minPer user
POST /api/capsules/import3/minPer user
POST /api/scripts/upload5/minPer user
POST /api/team/invitations10/minPer user
POST /api/team/secrets20/minPer user
PATCH /api/team/members/:id30/minPer user
PATCH /api/profile30/minPer user
POST /api/auth/validate-code5/minPer IP
GET /api/* (proxy layer)100/minPer user

Rate limited responses return HTTP 429 with a Retry-After header (seconds until reset).


Common Error Responses

StatusMeaning
400Validation error (check error field for details)
401Not authenticated
402Budget exceeded (job submission only)
403Forbidden (wrong role, suspended team, not owner)
404Resource not found
409Conflict (duplicate slug)
422Unprocessable (language detection failed, worker execution error)
429Rate limit exceeded
500Internal server error
502Worker unreachable
503Worker not configured
Last updated on