API Reference

Complete API documentation for MLStack.

Base URL

https://mlstack.io/api

Authentication

All API requests require an API key in the Authorization header:

Authorization: Bearer mlsk_your_api_key_here

Get your API key: Account Settings

Rate Limits

Endpoint Limit
LLM Inference (/llm/*) 60 requests/minute
Agent Execution (/agents/*) 30 requests/minute
API Key Creation 5 per hour
API Key Regeneration 10 per hour

See Rate Limits section below for details.


LLM Inference API

Submit Inference Job

Submit an LLM inference request (non-blocking).

Endpoint: POST /llm/predict

Headers:

Authorization: Bearer mlsk_your_key_here
Content-Type: application/json

Request Body:

{
  "prompt": "Your prompt here",
  "adapter_name": "your-adapter",
  "max_new_tokens": 256,
  "temperature": 0.7
}

Parameters:

Parameter Type Required Description
prompt string Yes Input text for the model
adapter_name string No* Use a specific LoRA adapter
base_model string No* Use base model (e.g., meta-llama/Llama-3.1-8B-Instruct)
schema_name string No Apply output schema by name
max_new_tokens integer No Max tokens to generate (default: 256)
temperature float No Sampling temperature 0-1 (default: 0.7)
structured boolean No Enable/disable structured output (default: true)

You must specify either* adapter_name OR base_model (not both).

Supported Base Models: - meta-llama/Llama-3.2-1B-Instruct - meta-llama/Llama-3.2-3B-Instruct - meta-llama/Llama-3.1-8B-Instruct - mistralai/Mistral-7B-Instruct-v0.3 - Qwen/Qwen2.5-14B-Instruct

Response (200 OK):

{
  "job_id": "fc-abc123",
  "status": "submitted"
}

Example:

import requests

response = requests.post(
    "https://mlstack.io/api/llm/predict",
    headers={
        "Authorization": "Bearer mlsk_your_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Explain quantum computing",
        "base_model": "meta-llama/Llama-3.1-8B-Instruct",
        "max_new_tokens": 150,
        "temperature": 0.7
    }
)

job_id = response.json()["job_id"]

Get Job Result

Poll for inference job result.

Endpoint: GET /llm/result/{job_id}

Headers:

Authorization: Bearer mlsk_your_key_here

Path Parameters:

Parameter Type Description
job_id string Job ID from submit response

Response - Processing (202 Accepted):

{
  "job_id": "fc-abc123",
  "status": "processing"
}

Response - Completed (200 OK):

{
  "job_id": "fc-abc123",
  "status": "completed",
  "output": "Quantum computing uses quantum bits...",
  "metadata": {
    "duration": 2.5,
    "tokens_generated": 150
  }
}

Response - Failed (500 Internal Server Error):

{
  "job_id": "fc-abc123",
  "status": "failed",
  "error": "Model timeout"
}

Status Values: - submitted - Job queued - processing - Currently running - completed - Successfully finished - failed - Error occurred

Example:

import time

while True:
    result = requests.get(
        f"https://mlstack.io/api/llm/result/{job_id}",
        headers={"Authorization": "Bearer mlsk_your_key"}
    )

    data = result.json()

    if data["status"] == "completed":
        print(f"Output: {data['output']}")
        break
    elif data["status"] == "failed":
        print(f"Error: {data['error']}")
        break

    time.sleep(1)

Agent API

Execute Agent

Submit a task for an agent to complete (non-blocking).

Endpoint: POST /agents/{agent_id}/execute

Headers:

Authorization: Bearer mlsk_your_key_here
Content-Type: application/json

Path Parameters:

Parameter Type Description
agent_id string Agent ID (from agent creation)

Request Body:

{
  "input": "User's question or task",
  "max_iterations": 5,
  "session_id": "optional-session-id"
}

Parameters:

Parameter Type Required Description
input string Yes User's query/task for the agent
max_iterations integer No Max tool calls allowed (default: 5)
session_id string No Session ID for multi-turn conversations (auto-generated if omitted)

Response (200 OK):

{
  "execution_id": "01HW9X...",
  "session_id": "01HW9Y...",
  "status": "pending",
  "message": "Agent execution started. Poll GET /api/agents/executions/{execution_id}"
}

Example:

response = requests.post(
    f"https://mlstack.io/api/agents/{agent_id}/execute",
    headers={
        "Authorization": "Bearer mlsk_your_key",
        "Content-Type": "application/json"
    },
    json={
        "input": "What's the status of order #12345?",
        "max_iterations": 5
    }
)

execution_id = response.json()["execution_id"]
session_id = response.json()["session_id"]

Get Execution Status

Poll for agent execution status and results.

Endpoint: GET /agents/executions/{execution_id}

Headers:

Authorization: Bearer mlsk_your_key_here

Path Parameters:

Parameter Type Description
execution_id string Execution ID from execute response

Response - Running (200 OK):

{
  "execution_id": "01HW9X...",
  "session_id": "01HW9Y...",
  "agent": {
    "id": "01HW8Z...",
    "name": "customer-support"
  },
  "status": "running",
  "input_text": "What's the status of order #12345?",
  "steps": [
    {
      "step": 1,
      "type": "llm_call",
      "response": {"action": "order_lookup", "order_id": "12345"}
    }
  ],
  "metrics": {
    "iteration_count": 1,
    "llm_call_count": 1,
    "tool_call_count": 0
  }
}

Response - Completed (200 OK):

{
  "execution_id": "01HW9X...",
  "session_id": "01HW9Y...",
  "agent": {
    "id": "01HW8Z...",
    "name": "customer-support"
  },
  "status": "completed",
  "input_text": "What's the status of order #12345?",
  "final_output": "Order #12345 is shipped and will arrive tomorrow",
  "steps": [
    {
      "step": 1,
      "type": "llm_call",
      "response": {"action": "order_lookup", "order_id": "12345"}
    },
    {
      "step": 2,
      "type": "tool_call",
      "tool_name": "order_lookup",
      "tool_input": {"order_id": "12345"},
      "tool_output": {"status": "shipped", "eta": "tomorrow"}
    },
    {
      "step": 3,
      "type": "llm_call",
      "response": {"action": "final_answer", "answer": "Order #12345..."}
    }
  ],
  "metrics": {
    "duration": 2.5,
    "iteration_count": 1,
    "llm_call_count": 2,
    "tool_call_count": 1
  },
  "created_at": "2026-03-11T10:00:00Z",
  "started_at": "2026-03-11T10:00:00Z",
  "completed_at": "2026-03-11T10:00:02Z"
}

Status Values: - pending - Queued for execution - running - Agent is processing - completed - Successfully finished - failed - Error occurred - max_iterations - Reached iteration limit

Example:

import time

while True:
    result = requests.get(
        f"https://mlstack.io/api/agents/executions/{execution_id}",
        headers={"Authorization": "Bearer mlsk_your_key"}
    )

    data = result.json()

    if data["status"] in ["completed", "failed", "max_iterations"]:
        break

    time.sleep(1)

if data["status"] == "completed":
    print(f"Answer: {data['final_output']}")
else:
    print(f"Error: {data['error_message']}")

Multi-Turn Conversations

Use session_id for contextual conversations:

# First message
response1 = requests.post(
    f"https://mlstack.io/api/agents/{agent_id}/execute",
    headers={"Authorization": "Bearer mlsk_your_key"},
    json={"input": "What's the weather in NYC?"}
)

session_id = response1.json()["session_id"]
# Poll and get result...

# Follow-up message (agent remembers context)
response2 = requests.post(
    f"https://mlstack.io/api/agents/{agent_id}/execute",
    headers={"Authorization": "Bearer mlsk_your_key"},
    json={
        "input": "Should I bring an umbrella?",
        "session_id": session_id
    }
)

Health Check

Endpoint: GET /health

Headers: None required

Response (200 OK):

{
  "status": "ok"
}

Error Responses

All errors return JSON with error and message fields.

400 Bad Request

Invalid request parameters.

{
  "error": "Bad Request",
  "message": "prompt is required"
}

Common causes: - Missing required fields - Invalid JSON format - Invalid parameter values - Cannot specify both adapter_name and base_model

401 Unauthorized

Missing or invalid API key.

{
  "error": "Authentication required",
  "message": "API key not provided or invalid"
}

Solutions: - Verify Authorization header is present - Check format: Bearer mlsk_... - Ensure key hasn't been revoked

402 Payment Required

Insufficient credits.

{
  "error": "Insufficient funds",
  "message": "Insufficient funds"
}

Solution: Add credits in Account Settings

403 Forbidden

No access to resource.

{
  "error": "Forbidden",
  "message": "You do not have access to this adapter"
}

Causes: - Trying to use private adapter owned by someone else - Accessing restricted endpoint

404 Not Found

Resource doesn't exist.

{
  "error": "Not Found",
  "message": "Adapter \"xyz\" not found"
}

Causes: - Incorrect adapter/agent name - Invalid job/execution ID - Resource deleted

429 Too Many Requests

Rate limit exceeded.

{
  "status": "failed",
  "message": "Rate limit exceeded."
}

Solution: Slow down requests. See Rate Limits below.

500 Internal Server Error

Server-side error.

{
  "error": "Internal server error",
  "message": "An unexpected error occurred"
}

Solution: Retry request. Contact support if persists.

503 Service Unavailable

Service temporarily down.

{
  "error": "Service Unavailable",
  "message": "LLM service not configured"
}

Solution: Wait and retry.

504 Gateway Timeout

Request timed out.

{
  "error": "Request Timeout",
  "message": "LLM service timeout"
}

Solution: Retry. Service may be cold-starting.


Rate Limits

Current Limits

Endpoint Limit Window
/llm/predict 60 requests per minute
/llm/result/{job_id} 60 requests per minute
/agents/{id}/execute 30 requests per minute
/agents/executions/{id} 60 requests per minute
API Key Creation 5 keys per hour
API Key Regeneration 10 keys per hour

Rate Limit Headers

Responses include rate limit info:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1709035200

Best Practices

1. Exponential Backoff

import time

def make_request_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(url, ...)

        if response.status_code == 429:
            wait_time = 2 ** attempt  # 1s, 2s, 4s
            time.sleep(wait_time)
            continue

        return response

    raise Exception("Max retries exceeded")

2. Monitor Remaining Requests

response = requests.post(...)
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))

if remaining < 10:
    print("Warning: Approaching rate limit")

3. Batch Operations

Submit all jobs first, then poll:

# Submit all
job_ids = [
    submit_inference(prompt)["job_id"] 
    for prompt in prompts
]

# Then poll
results = [poll_result(jid) for jid in job_ids]

Increasing Limits

Need higher limits? Contact [email protected] with: - Your use case - Expected request volume - Business justification


Error Handling Example

import requests
import time

def submit_inference(prompt, adapter_name):
    """Submit inference with error handling"""
    try:
        response = requests.post(
            "https://mlstack.io/api/llm/predict",
            headers={"Authorization": f"Bearer {API_KEY}"},
            json={
                "prompt": prompt,
                "adapter_name": adapter_name
            }
        )

        if response.status_code == 200:
            return response.json()["job_id"]
        elif response.status_code == 401:
            raise Exception("Invalid API key")
        elif response.status_code == 402:
            raise Exception("Insufficient credits")
        elif response.status_code == 429:
            # Rate limited - wait and retry
            time.sleep(60)
            return submit_inference(prompt, adapter_name)
        else:
            error = response.json()
            raise Exception(f"{error['error']}: {error['message']}")

    except requests.exceptions.RequestException as e:
        raise Exception(f"Network error: {e}")


def poll_result(job_id, timeout=120):
    """Poll for result with timeout"""
    start = time.time()

    while time.time() - start < timeout:
        try:
            response = requests.get(
                f"https://mlstack.io/api/llm/result/{job_id}",
                headers={"Authorization": f"Bearer {API_KEY}"}
            )

            data = response.json()

            if data["status"] == "completed":
                return data["output"]
            elif data["status"] == "failed":
                raise Exception(f"Job failed: {data['error']}")

            time.sleep(1)

        except requests.exceptions.RequestException as e:
            # Network error - retry
            time.sleep(5)
            continue

    raise Exception("Timeout waiting for result")

Next Steps