Authentication
HITL.sh uses API key authentication for secure access to the API. All requests must include your API key in the Authorization header using the Bearer token format.
API Key Authentication
API keys are designed for server-to-server communication and automated workflows. They provide access to the HITL.sh API at https://api.hitl.sh/v1.
Getting Your API Key
Log in to your HITL.sh dashboard
Navigate to Settings → API Keys
Click “Create New API Key”
Copy the generated key (shown only once)
Store securely in your environment variables
Using API Keys
Include your API key in the Authorization header with the Bearer prefix:
Using the API Playground : When testing endpoints in the documentation playground, enter your API key in the format: Bearer your_api_key_here (including the word “Bearer” and a space before your key).
curl -H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
https://api.hitl.sh/v1/api/loops
import requests
headers = {
'Authorization' : 'Bearer your_api_key_here' ,
'Content-Type' : 'application/json'
}
response = requests.get( 'https://api.hitl.sh/v1/api/loops' , headers = headers)
const axios = require ( 'axios' );
const headers = {
'Authorization' : 'Bearer your_api_key_here' ,
'Content-Type' : 'application/json'
};
const response = await axios . get ( 'https://api.hitl.sh/v1/api/loops' , { headers });
package main
import (
" net/http "
)
func main () {
req , _ := http . NewRequest ( "GET" , "https://api.hitl.sh/v1/api/loops" , nil )
req . Header . Set ( "Authorization" , "Bearer your_api_key_here" )
req . Header . Set ( "Content-Type" , "application/json" )
client := & http . Client {}
resp , _ := client . Do ( req )
}
<? php
$curl = curl_init ();
curl_setopt_array ( $curl , [
CURLOPT_URL => "https://api.hitl.sh/v1/api/loops" ,
CURLOPT_RETURNTRANSFER => true ,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer your_api_key_here" ,
"Content-Type: application/json"
],
]);
$response = curl_exec ( $curl );
curl_close ( $curl );
?>
API Key Rate Limits
Each API key has the following limits:
Rate Limits
100 requests per hour per API key
Resets at the top of each hour (e.g., 1:00 PM, 2:00 PM)
Rate limit headers included in all responses
X-RateLimit-Reset shows exact UTC timestamp of next reset
Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 1642237200
API Key Permissions
API keys have specific permissions based on your account:
Create new loops
View loops you created or are a member of
Update and delete loops you created (creator only)
Add/remove members from loops you created (creator only)
View loop statistics and member lists
Create requests in loops you created
View requests in loops you’re a member of
Cancel your own requests
Add feedback to completed requests you created
Access request history and response data
Security Best Practices
API Key Security
Environment Variables
Store API keys in environment variables, never in code: export HITL_API_KEY = "your_api_key_here"
import os
api_key = os.environ.get( 'HITL_API_KEY' )
Key Rotation
Rotate API keys regularly:
Set up automatic rotation (recommended: every 90 days)
Have a backup key ready before rotating
Update all systems using the old key
Least Privilege
Use separate API keys for different environments:
Development keys with limited permissions
Production keys with full access
Testing keys for CI/CD pipelines
Monitor Usage
Track API key usage in your dashboard:
Monitor request patterns for anomalies
Set up alerts for unusual activity
Review access logs regularly
Always use HTTPS and proper security headers:
import requests
headers = {
'Authorization' : 'Bearer your_api_key_here' ,
'Content-Type' : 'application/json' ,
'User-Agent' : 'YourApp/1.0.0' ,
'Accept' : 'application/json'
}
# Always use HTTPS
response = requests.get( 'https://api.hitl.sh/v1/api/loops' , headers = headers)
Error Handling
Authentication Errors
401 Unauthorized - Invalid API Key
{
"error" : true ,
"msg" : "Invalid API key"
}
Solutions:
Verify API key is correct (no typos or extra spaces)
Check if key has been revoked or deleted
Regenerate a new API key if needed
Ensure you’re not using an old/expired key
401 Unauthorized - Inactive API Key
{
"error" : true ,
"msg" : "API key is inactive"
}
Solutions:
Check API key status in your dashboard
Reactivate the key if it was disabled
Generate a new API key if needed
403 Forbidden - Insufficient Permissions
{
"error" : true ,
"msg" : "Access denied to this resource"
}
Solutions:
Check API key permissions
Verify resource ownership
Contact support for permission updates
{
"error" : true ,
"msg" : "API rate limit exceeded" ,
"data" : {
"usage_count" : 100 ,
"usage_limit" : 100 ,
"remaining" : 0
}
}
Solutions:
Wait for rate limit reset
Implement exponential backoff
Upgrade to higher tier if needed
Retry Logic
Implement robust retry logic for authentication failures:
import time
import requests
from functools import wraps
def retry_auth ( max_retries = 3 ):
def decorator ( func ):
@wraps (func)
def wrapper ( * args , ** kwargs ):
for attempt in range (max_retries):
try :
response = func( * args, ** kwargs)
if response.status_code == 401 :
# Log the authentication failure
print ( f "Authentication failed on attempt { attempt + 1 } " )
if attempt < max_retries - 1 :
# Wait before retrying (maybe refresh API key)
time.sleep( 2 ** attempt)
continue
return response
except Exception as e:
if attempt == max_retries - 1 :
raise e
time.sleep( 2 ** attempt) # Exponential backoff
return None
return wrapper
return decorator
@retry_auth ()
def make_api_request ( url , headers ):
return requests.get(url, headers = headers)
async function makeRequestWithRetry ( url , options , maxRetries = 3 ) {
for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
try {
const response = await fetch ( url , options );
if ( response . status === 401 ) {
console . log ( `Authentication failed on attempt ${ attempt + 1 } ` );
if ( attempt < maxRetries - 1 ) {
// Wait before retrying
await new Promise ( resolve =>
setTimeout ( resolve , 2 ** attempt * 1000 )
);
continue ;
}
}
return response ;
} catch ( error ) {
if ( attempt === maxRetries - 1 ) throw error ;
await new Promise ( resolve =>
setTimeout ( resolve , 2 ** attempt * 1000 )
);
}
}
}
Testing Authentication
API Key Testing
Use the dedicated test endpoint to verify your API key:
# Test API key validity and get account info
curl -H "Authorization: Bearer your_api_key_here" \
https://api.hitl.sh/v1/test
# Expected response for valid key:
{
"error" : false ,
"msg" : "API key is valid",
"data" : {
"api_key_id" : "65f1234567890abcdef12349",
"user_id" : "65f1234567890abcdef12346",
"email" : "user@example.com",
"account_status" : "active",
"rate_limit" : {
"limit" : 100,
"remaining" : 95,
"reset_at" : "2024-03-15T15:00:00Z"
},
"permissions" : [ "loops:read" , "loops:write", "requests:read", "requests:write"]
}
}
# Expected response for invalid key:
{
"error" : true ,
"msg" : "Invalid API key"
}
The /test endpoint provides detailed information about your API key, including rate limits and permissions. Use this for debugging and monitoring.
Debug Authentication Issues
Use verbose curl to debug authentication problems:
# Verbose request to see headers and response
curl -v -H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
https://api.hitl.sh/v1/api/loops
# Check if your header is being sent correctly
curl -H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-w "HTTP Status: %{http_code}\n" \
https://api.hitl.sh/v1/api/loops
Environment-Specific Testing
Test across different environments:
import os
import requests
# Load environment-specific API key
def get_api_key ():
env = os.environ.get( 'ENVIRONMENT' , 'development' )
key_mapping = {
'development' : os.environ.get( 'HITL_DEV_API_KEY' ),
'staging' : os.environ.get( 'HITL_STAGING_API_KEY' ),
'production' : os.environ.get( 'HITL_PROD_API_KEY' )
}
return key_mapping.get(env)
def test_authentication ():
api_key = get_api_key()
if not api_key:
raise ValueError ( "API key not found for current environment" )
headers = {
'Authorization' : f 'Bearer { api_key } ' ,
'Content-Type' : 'application/json'
}
response = requests.get( 'https://api.hitl.sh/v1/api/loops' , headers = headers)
if response.status_code == 200 :
print ( "✅ Authentication successful" )
return True
else :
print ( f "❌ Authentication failed: { response.json() } " )
return False
# Test authentication
test_authentication()
Next Steps
Create Your First Loop Start using your API key to create loops and manage workflows.
Error Handling Guide Learn how to handle and debug authentication errors effectively.
Webhooks Use callback URLs to receive notifications when requests complete.