API Reference
Complete API documentation for MLStack.
Base URL
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):
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 |
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