HarvestGPU Documentation

HarvestGPU is a BYOK (Bring Your Own Key) GPU routing platform. Connect your own GPU provider API keys, submit jobs through a single API, and we route them to the cheapest available GPU across all your accounts.

Getting Started

HarvestGPU works with your existing GPU provider accounts. Here is how to get set up:

1. Create a HarvestGPU account

Sign up at /register or via the API. This gives you a HarvestGPU API key for authenticating requests.

2. Connect your GPU provider keys

Go to Dashboard Settings and add your API keys for one or more providers. You can also use the API:

curl -X POST http://localhost:5000/api/v1/providers/keys \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"provider": "runpod", "api_key": "YOUR_RUNPOD_KEY", "label": "My RunPod"}'

3. Submit jobs

Jobs are routed across your connected providers to find the cheapest option. A built-in mock provider is always available for testing, even without any provider keys.

Supported providers and where to get API keys

ProviderSlugAPI Key Page
RunPodrunpodrunpod.io/console/user/settings
Lambda Labslambdacloud.lambdalabs.com/api-keys
Vast.aivastaicloud.vast.ai/account
TensorDocktensordockmarketplace.tensordock.com/api

Your keys are stored securely and only used to call provider APIs on your behalf. Billing for GPU usage goes directly through your provider accounts.

Quick Start

Get running in under a minute.

1. Get your API key

curl -X POST http://localhost:5000/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your-password"}'

Save the api_key from the response. It looks like hg_live_abc123...

2. Submit a GPU job

curl -X POST http://localhost:5000/api/v1/jobs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gpu": "H100",
    "image": "pytorch/pytorch:latest",
    "command": "python train.py",
    "priority": "cost"
  }'

3. Check job status

curl http://localhost:5000/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer YOUR_API_KEY"

Authentication

All authenticated endpoints accept two auth methods:

  • API Key (recommended): Pass your API key as a Bearer token: Authorization: Bearer hg_live_...
  • API Key Header: X-API-Key: hg_live_...
  • JWT Token: Obtained from the login endpoint. Same Bearer header format.

Python SDK

Installation

pip install harvestgpu

Usage

from harvestgpu import HarvestGPU

gpu = HarvestGPU(api_key="hg_live_...")

# Submit a job - routes to cheapest provider
job = gpu.run(
    gpu="H100",
    image="pytorch/pytorch:latest",
    command="python train.py",
    budget_max=2.50,
)

print(job.status)        # "running"
print(job.provider)      # "mock" (or real provider)
print(job.cost_per_hour) # 2.86

# List your jobs
jobs = gpu.jobs()
for j in jobs:
    print(f"{j.id}: {j.gpu_type} on {j.provider} - {j.status}")

# Get current GPU pricing
pricing = gpu.pricing()
for p in pricing:
    print(f"{p.gpu_model}: ${p.price}/hr via {p.provider}")

# Stop a job
job.stop()

# Get logs
logs = job.logs()
print(logs)

CLI Tool

# Authenticate
harvestgpu auth login --key hg_live_...
harvestgpu auth whoami

# Run a GPU job
harvestgpu run --gpu H100 --image pytorch/pytorch:latest --command "python train.py"

# Manage jobs
harvestgpu jobs list
harvestgpu jobs status JOB_ID
harvestgpu jobs logs JOB_ID
harvestgpu jobs stop JOB_ID

# Check pricing
harvestgpu pricing
harvestgpu pricing --gpu H100

API Reference

Base URL: http://localhost:5000/api/v1

All responses follow this envelope:

{
  "status": "ok",      // or "error"
  "data": { ... },     // present on success
  "error": "message"   // present on error
}

Auth Endpoints

POST
/api/v1/auth/register

Create a new account and get an API key.

Request Body

{
  "email": "you@example.com",
  "password": "min8chars",
  "company": "optional"
}

Response

{
  "status": "ok",
  "data": {
    "user_id": "abc123",
    "email": "you@example.com",
    "api_key": "hg_live_xyz...",
    "token": "jwt.token.here"
  }
}
POST
/api/v1/auth/login

Login and get a JWT token.

Request Body

{"email": "you@example.com", "password": "your-password"}
GET
/api/v1/auth/me

Get current user info, usage, and active jobs. Requires auth.

Job Endpoints

POST
/api/v1/jobs

Submit a new GPU job. We route to the best provider based on your priority.

Request Body

{
  "gpu": "H100",                        // required
  "image": "pytorch/pytorch:latest",    // Docker image
  "command": "python train.py",         // Command to run
  "budget_max_per_hour": 2.50,          // optional price cap
  "max_duration_hours": 4,              // optional max runtime
  "priority": "cost"                    // "cost" | "speed" | "availability"
}
GET
/api/v1/jobs

List your jobs with optional filters.

Query Parameters

  • status - Filter: running, completed, failed, stopped, queued
  • gpu - Filter by GPU type
  • provider - Filter by provider slug
  • limit - Results per page (default 50, max 100)
  • offset - Pagination offset
GET
/api/v1/jobs/:job_id

Get details for a specific job.

POST
/api/v1/jobs/:job_id/stop

Stop a running job. Charges for compute used so far.

GET
/api/v1/jobs/:job_id/logs

Get logs for a job. Live-streams for running jobs.

Provider Endpoints

GET
/api/v1/providers

List all providers and their availability. No auth required.

GET
/api/v1/providers/:slug/gpus

List available GPUs from a specific provider.

GET
/api/v1/pricing

Real-time pricing matrix across all providers. No auth required.

Provider Key Endpoints

POST
/api/v1/providers/keys

Add or update a provider API key. Requires auth.

Request Body

{
  "provider": "runpod",           // runpod | lambda | vastai | tensordock
  "api_key": "your-provider-key",
  "label": "My RunPod Account"    // optional
}
GET
/api/v1/providers/keys

List connected providers. Returns provider name, last 4 chars of key, label, and active status. Does not return full keys. Requires auth.

DELETE
/api/v1/providers/keys/:provider

Remove a provider key. Requires auth.

POST
/api/v1/providers/keys/:provider/test

Test if a stored key is valid by calling the provider's API. Requires auth.

Response

{
  "status": "ok",
  "data": {
    "provider": "runpod",
    "valid": true,
    "message": "Key is valid"
  }
}

Usage Endpoints

GET
/api/v1/billing/usage

Current period usage with daily breakdown. Requires auth.

GET
/api/v1/billing/history

Past usage records. Requires auth.

Webhook Endpoints

GET
/api/v1/webhooks

List your configured webhooks. Requires auth.

POST
/api/v1/webhooks

Create a new webhook.

Request Body

{"url": "https://your-app.com/webhook", "events": "job.completed,job.failed"}
DELETE
/api/v1/webhooks/:id

Delete a webhook. Requires auth.

Webhook Events

When configured, we send HTTP POST requests to your webhook URL with these events:

  • job.completed - Job finished successfully
  • job.failed - Job encountered an error
  • job.stopped - Job was manually stopped

Payload Format

{
  "event": "job.completed",
  "job_id": "abc123",
  "gpu_type": "H100",
  "provider": "runpod",
  "total_cost": 3.45,
  "status": "completed",
  "timestamp": "2026-04-14T12:00:00Z"
}

Rate Limits

PlanRequests/minuteJobs/hour
Free6010
Pay As You Go1,000100
Enterprise10,000Unlimited

Error Handling

All errors return this format:

{
  "status": "error",
  "error": "Human-readable error message"
}
HTTP CodeMeaning
400Bad request (missing or invalid parameters)
401Authentication required or invalid
404Resource not found
503No providers available for the request