Files
aitbc/docs/developer/tutorials/coordinator-api-integration.md
oib 329b3beeba ```
feat: add SQLModel relationships, fix ZK verifier circuit integration, and complete Stage 19-20 documentation

- Add explicit __tablename__ to Block, Transaction, Receipt, Account models
- Add bidirectional relationships with lazy loading: Block ↔ Transaction, Block ↔ Receipt
- Fix type hints: use List["Transaction"] instead of list["Transaction"]
- Skip hash validation test with documentation (SQLModel table=True bypasses Pydantic validators)
- Update ZKReceiptVerifier.sol to match receipt_simple circuit (
2026-01-24 18:34:37 +01:00

7.7 KiB

Integrating with Coordinator API

This tutorial shows how to integrate your application with the AITBC Coordinator API.

API Overview

The Coordinator API is the central hub for:

  • Job submission and management
  • Miner registration and discovery
  • Receipt generation and verification
  • Network statistics

Base URL: https://aitbc.bubuit.net/api

Authentication

Public Endpoints

Some endpoints are public and don't require authentication:

  • GET /health - Health check
  • GET /v1/stats - Network statistics

Authenticated Endpoints

For job submission and management, use an API key:

curl -H "X-Api-Key: your-api-key" https://aitbc.bubuit.net/api/v1/jobs

Core Endpoints

Jobs

Submit a Job

POST /v1/jobs
Content-Type: application/json

{
  "prompt": "Explain quantum computing",
  "model": "llama3.2",
  "params": {
    "max_tokens": 256,
    "temperature": 0.7
  }
}

Response:

{
  "job_id": "job-abc123",
  "status": "pending",
  "created_at": "2026-01-24T15:00:00Z"
}

Get Job Status

GET /v1/jobs/{job_id}

Response:

{
  "job_id": "job-abc123",
  "status": "completed",
  "result": "Quantum computing is...",
  "miner_id": "miner-xyz",
  "started_at": "2026-01-24T15:00:01Z",
  "completed_at": "2026-01-24T15:00:05Z"
}

List Jobs

GET /v1/jobs?status=completed&limit=10

Cancel a Job

POST /v1/jobs/{job_id}/cancel

Miners

Register Miner

POST /v1/miners/register
Content-Type: application/json

{
  "miner_id": "my-miner-001",
  "capabilities": ["llama3.2", "codellama"],
  "gpu_info": {
    "name": "NVIDIA RTX 4090",
    "memory": "24GB"
  }
}

Get Available Jobs (for miners)

GET /v1/jobs/available?miner_id=my-miner-001

Claim a Job

POST /v1/jobs/{job_id}/claim
Content-Type: application/json

{
  "miner_id": "my-miner-001"
}

Complete a Job

POST /v1/jobs/{job_id}/complete
Content-Type: application/json

{
  "miner_id": "my-miner-001",
  "result": "The generated output...",
  "completed_at": "2026-01-24T15:00:05Z"
}

Receipts

Get Receipt

GET /v1/receipts/{receipt_id}

List Receipts

GET /v1/receipts?client=ait1client...&limit=20

Explorer Endpoints

GET /explorer/blocks          # Recent blocks
GET /explorer/transactions    # Recent transactions
GET /explorer/receipts        # Recent receipts
GET /explorer/stats           # Network statistics

Python Integration

Using httpx

import httpx

class CoordinatorClient:
    def __init__(self, base_url: str, api_key: str = None):
        self.base_url = base_url
        self.headers = {}
        if api_key:
            self.headers["X-Api-Key"] = api_key
        self.client = httpx.Client(headers=self.headers, timeout=30.0)
    
    def submit_job(self, prompt: str, model: str = "llama3.2", **params) -> dict:
        response = self.client.post(
            f"{self.base_url}/v1/jobs",
            json={"prompt": prompt, "model": model, "params": params}
        )
        response.raise_for_status()
        return response.json()
    
    def get_job(self, job_id: str) -> dict:
        response = self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
        response.raise_for_status()
        return response.json()
    
    def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
        import time
        start = time.time()
        while time.time() - start < timeout:
            job = self.get_job(job_id)
            if job["status"] in ["completed", "failed", "cancelled"]:
                return job
            time.sleep(2)
        raise TimeoutError(f"Job {job_id} did not complete in {timeout}s")

# Usage
client = CoordinatorClient("https://aitbc.bubuit.net/api")
job = client.submit_job("Hello, world!")
result = client.wait_for_job(job["job_id"])
print(result["result"])

Async Version

import httpx
import asyncio

class AsyncCoordinatorClient:
    def __init__(self, base_url: str, api_key: str = None):
        self.base_url = base_url
        headers = {"X-Api-Key": api_key} if api_key else {}
        self.client = httpx.AsyncClient(headers=headers, timeout=30.0)
    
    async def submit_job(self, prompt: str, model: str = "llama3.2") -> dict:
        response = await self.client.post(
            f"{self.base_url}/v1/jobs",
            json={"prompt": prompt, "model": model}
        )
        response.raise_for_status()
        return response.json()
    
    async def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
        start = asyncio.get_event_loop().time()
        while asyncio.get_event_loop().time() - start < timeout:
            response = await self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
            job = response.json()
            if job["status"] in ["completed", "failed"]:
                return job
            await asyncio.sleep(2)
        raise TimeoutError()

# Usage
async def main():
    client = AsyncCoordinatorClient("https://aitbc.bubuit.net/api")
    job = await client.submit_job("Explain AI")
    result = await client.wait_for_job(job["job_id"])
    print(result["result"])

asyncio.run(main())

JavaScript Integration

class CoordinatorClient {
  constructor(baseUrl, apiKey = null) {
    this.baseUrl = baseUrl;
    this.headers = { 'Content-Type': 'application/json' };
    if (apiKey) this.headers['X-Api-Key'] = apiKey;
  }

  async submitJob(prompt, model = 'llama3.2', params = {}) {
    const response = await fetch(`${this.baseUrl}/v1/jobs`, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify({ prompt, model, params })
    });
    return response.json();
  }

  async getJob(jobId) {
    const response = await fetch(`${this.baseUrl}/v1/jobs/${jobId}`, {
      headers: this.headers
    });
    return response.json();
  }

  async waitForJob(jobId, timeout = 60000) {
    const start = Date.now();
    while (Date.now() - start < timeout) {
      const job = await this.getJob(jobId);
      if (['completed', 'failed', 'cancelled'].includes(job.status)) {
        return job;
      }
      await new Promise(r => setTimeout(r, 2000));
    }
    throw new Error('Timeout');
  }
}

// Usage
const client = new CoordinatorClient('https://aitbc.bubuit.net/api');
const job = await client.submitJob('Hello!');
const result = await client.waitForJob(job.job_id);
console.log(result.result);

Error Handling

HTTP Status Codes

Code Meaning
200 Success
201 Created
400 Bad Request (invalid parameters)
401 Unauthorized (invalid API key)
404 Not Found
429 Rate Limited
500 Server Error

Error Response Format

{
  "detail": "Job not found",
  "error_code": "JOB_NOT_FOUND"
}

Retry Logic

import time
from httpx import HTTPStatusError

def with_retry(func, max_retries=3, backoff=2):
    for attempt in range(max_retries):
        try:
            return func()
        except HTTPStatusError as e:
            if e.response.status_code == 429:
                retry_after = int(e.response.headers.get("Retry-After", backoff))
                time.sleep(retry_after)
            elif e.response.status_code >= 500:
                time.sleep(backoff * (attempt + 1))
            else:
                raise
    raise Exception("Max retries exceeded")

Webhooks (Coming Soon)

Register a webhook to receive job completion notifications:

POST /v1/webhooks
Content-Type: application/json

{
  "url": "https://your-app.com/webhook",
  "events": ["job.completed", "job.failed"]
}

Next Steps