REST API

HTTP API for jobs, models, hosts, wallets, and API keys. Base URL: https://metalcloud.space/api/v1.

Authentication

Send an API key as a bearer token. Keys start with mc_ and are created in the API keys dashboard. The full key is returned once, on create.

HTTP
Authorization: Bearer mc_your_key

Job routes also accept the same key in X-API-Key. Login returns a JWT you can send the same way. A missing or unknown token returns 401.

Error
{
  "success": false,
  "message": "Invalid or expired token"
}

Jobs

/api/v1/jobs is the customer job API. Create a job with the Python client or with JSON.

Python
from metalcloud import Client

client = Client(api_key="mc_...")
job = client.jobs.submit(
    type="inference",
    model_id="mlx-community/Llama-3.2-1B",
    input={"prompt": "Explain unified memory in one sentence."},
    priority="normal",
    min_memory_gb=16,
)
result = job.wait()

model_id must be a repo installed on a host you can reach. See the model library. The example id is the shape hosts report. It is not a promise that every Mac has that model cached.

MethodPathPurpose
POST/jobsSubmit a job
GET/jobsList your jobs. Query: status, type, limit (max 100), offset
GET/jobs/{uuid}Job status, host, billing, input, and output
POST/jobs/estimateCost estimate before you submit
GET/jobs/queueQueue status
POST/jobs/{uuid}/cancelCancel a pending, queued, assigned, or running job
POST/jobs/{uuid}/retrySubmit a cancelled job again, or a failed inference job
GET/jobs/{uuid}/logsLogs. Query: level, limit (max 500)
GET/jobs/{uuid}/outputOutput once the job is completed or failed

Create body

FieldRules
typeinference, training, fine_tuning, batch, or container. Default inference. Customers normally send inference.
model_idUp to 255 characters. Letters, numbers, and - _ / : .
inputJSON object, 10 MB maximum. Put prompt and optional max_tokens here.
prioritylow, normal, high, or critical
min_memory_gb8 to 512
min_gpu_cores8 to 80
max_duration_minutes1 to 1440. Default 60
host_uuidsOptional list of host UUIDs, 50 maximum
required_chipOptional chip, for example M3_Ultra or M5_Max

Send X-Idempotency-Key (16 to 64 characters) to make a retry return the job created in the last 24 hours instead of a second job. For inference and batch, a max_tokens value equal to the model context length is dropped, and any larger value is cut to the job duration at 25 tokens per second.

A successful create returns success: true and data.job with uuid, type, priority, and status (assigned when a host is free, otherwise queued), plus data.estimate. Status values are pending, queued, assigned, running, completed, failed, cancelled, and timeout.

You can have 10 jobs in pending, queued, assigned, or running at once. Limits per hour: 60 submits, 300 lists, 2,400 status reads, 30 cancels. No matching host returns 503. A balance below the maximum estimate returns 402 with required and available.

Models

These routes need a bearer token. hosts is a comma-separated list of host UUIDs, 50 maximum. Details are in the model library.

MethodPathPurpose
GET/models?hosts={uuids}Models cached on those hosts while they are online
GET/models/search?hosts={uuids}&q=Search public MLX repos. q is optional and at most 200 characters
GET/models/context?repo_id=Context length published in the model config. 404 when the model does not publish one
POST/hosts/{uuid}/model-downloadsBody {"repo_id": "org/name"}. Starts a download on that host
GET/hosts/{uuid}/model-downloadsActive downloads for a host
GET/model-downloads/{download_id}One download
POST/model-downloads/{download_id}/cancelCancel a download
POST/hosts/{uuid}/model-removalsBody {"repo_id": "org/name"}. Deletes that model on the host when you downloaded the copy that is installed there
GET/hosts/{uuid}/model-removalsYour active removals on that host
GET/model-removals/{removal_id}One of your removals

Hosts

GET /hosts lists machines with a heartbeat in the last two minutes. GET /hosts/{uuid} returns one active host, including chip_model, memory_gb, gpu_cores, and hourly_rate_gbp. POST /hosts registers a machine and needs a bearer token. Required fields: name, chip_model, memory_gb, gpu_cores, cpu_cores, hourly_rate_gbp.

Wallet and account

MethodPathPurpose
GET/healthNo auth. status, version, database state
POST/auth/registeremail, password, name, optional role (customer, host, or both)
POST/auth/loginemail and password. Returns a token
POST/auth/forgot-passwordStart a password reset
POST/auth/reset-passwordFinish a password reset
GET/auth/meThe signed-in account
GET/walletbalance, pending, lifetime_earned, lifetime_spent, in GBP
GET/wallet/transactionsRecent transactions
GET/dashboard/statsJob counts, compute hours, balance, and spend

Add funds in the billing dashboard. Rates are on the billing page.

API keys

MethodPathPurpose
GET/api-keysList keys. Secrets are not returned
POST/api-keysBody {"name": "my-app"}. The token is shown once
DELETE/api-keys/{id}Revoke a key

Host dashboard

These routes need a host or admin account.

MethodPathPurpose
GET/host/machinesMacs linked to the account, including online state
GET/host/statsHost totals
GET/host/jobsJobs run on your machines
GET/host/earningsEarnings. Optional month=YYYY-MM
GET/host/payoutsPayout history
POST/host/payoutsRequest a payout

Machine setup for hosts is in host setup.