OutLayer Documentation
HTTPS API
Call OutLayer projects via simple HTTP requests without NEAR transactions. Authentication uses Payment Keys with prepaid USD stablecoin balance.
Overview#
NEAR Transactions
- Payment: NEAR tokens
- Latency: ~2-3 seconds
- Response: callback to contract
HTTPS API
- Payment: USD stablecoins
- Latency: instant (sync mode)
- Response: HTTP response body
# Simple example
curl -X POST https://api.outlayer.io/call/alice.near/my-assistant \
-H "X-Payment-Key: bob.near:0:K7xR2mN9pQs5vW3yZ8bF..." \
-H "Content-Type: application/json" \
-d '{"input": {"prompt": "Hello!"}}'Request Format#
Endpoint#
POST https://api.outlayer.io/call/{project_owner}/{project_name}Example: POST https://api.outlayer.io/call/alice.near/weather-api
Request Headers#
| Header | Required | Default | Description |
|---|---|---|---|
| X-Payment-Key | Yes | - | Format: owner:nonce:secretAuthentication for the API call |
| X-Compute-Limit | No | 10000 | Max compute budget in USD micro-units 10000 = $0.01, 100000 = $0.10 |
| X-Attached-Deposit | No | 0 | Payment to project author in USD micro-units 1000000 = $1.00. Goes to author's earnings. |
| Content-Type | No | application/json | Request body format |
X-Attached-Deposit vs X-Compute-Limit:
X-Compute-Limit- pays for infrastructure (OutLayer), refunded if unusedX-Attached-Deposit- pays the project author, charged immediately
Request Body#
{
"input": { // Required - passed to WASM as stdin
"prompt": "Hello, AI!",
"temperature": 0.7
},
"resource_limits": { // Optional - override project defaults
"max_instructions": 10000000000,
"max_memory_mb": 128,
"max_execution_seconds": 60
},
"async": false // Optional - sync (default) or async mode
}| Field | Type | Required | Description |
|---|---|---|---|
| input | object | Yes | Passed to WASM code as JSON via stdin |
| resource_limits | object | No | Override project's default limits |
| async | boolean | No | false = wait for result, true = return call_id immediately |
Resource Limits#
| Limit | Default | Maximum | Description |
|---|---|---|---|
| max_instructions | 1 billion | 500 billion | WASM instructions to execute |
| max_memory_mb | 128 MB | 512 MB | Memory available to WASM |
| max_execution_seconds | 60 sec | 180 sec | Wall-clock timeout |
Response Format#
Synchronous Response (default)#
When async: false (default), the request waits until execution completes:
// Success
{
"call_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"output": "Here's the weather forecast for...",
"compute_cost": "45000",
"job_id": 12345,
"attestation_url": "https://outlayer.io/attestations/12345"
}
// Failure
{
"call_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"error": "Execution timeout after 60 seconds",
"compute_cost": "100000",
"job_id": 12345
}Asynchronous Response#
When async: true, the request returns immediately with a call_id for polling:
// Initial response
{
"call_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"poll_url": "https://api.outlayer.io/calls/550e8400-e29b-41d4-a716-446655440000"
}Poll the result using GET /calls/{call_id}:
curl -H "X-Payment-Key: bob.near:0:..." \
https://api.outlayer.io/calls/550e8400-e29b-41d4-a716-446655440000Response Fields#
| Field | Type | Description |
|---|---|---|
| call_id | UUID | Unique identifier for this API call |
| status | string | "pending", "completed", or "failed" |
| output | any | WASM stdout (only when completed) |
| error | string | Error message (only when failed) |
| compute_cost | string | Actual USD cost in micro-units (e.g., "45000" = $0.045). Charged even on failure. |
| job_id | number | Internal job ID for attestation lookup |
| attestation_url | string | Link to TEE attestation (completed only) |
Environment Variables in WASM#
Your WASM code can detect the execution context and access payment information via environment variables. Values differ between NEAR transactions and HTTPS API calls:
| Variable | NEAR | HTTPS |
|---|---|---|
| OUTLAYER_EXECUTION_TYPE | "NEAR" | "HTTPS" |
| NEAR_SENDER_ID | Transaction signer | Payment Key owner |
| USD_PAYMENT | "0" | X-Attached-Deposit value |
| NEAR_PAYMENT_YOCTO | Attached NEAR | "0" |
| OUTLAYER_CALL_ID | "" | call_id UUID |
| NEAR_TRANSACTION_HASH | Transaction hash | "" |
| NEAR_BLOCK_HEIGHT | Block number | "" |
| NEAR_BLOCK_TIMESTAMP | Block timestamp | "" |
| OUTLAYER_PROJECT_ID | owner/name (same for both) | |
Detecting Execution Mode#
let execution_type = std::env::var("OUTLAYER_EXECUTION_TYPE")
.unwrap_or_else(|_| "NEAR".to_string());
match execution_type.as_str() {
"HTTPS" => {
// HTTPS API call
let usd_payment: u64 = std::env::var("USD_PAYMENT")
.unwrap_or_else(|_| "0".to_string())
.parse()
.unwrap_or(0);
let call_id = std::env::var("OUTLAYER_CALL_ID").unwrap_or_default();
let cost = usd_payment as f64 / 1_000_000.0;
println!("HTTPS call {}: paid {} USD", call_id, cost);
}
"NEAR" => {
// NEAR transaction
let near_payment: u128 = std::env::var("NEAR_PAYMENT_YOCTO")
.unwrap_or_else(|_| "0".to_string())
.parse()
.unwrap_or(0);
let tx_hash = std::env::var("NEAR_TRANSACTION_HASH").unwrap_or_default();
println!("NEAR tx {}: paid {} yoctoNEAR", tx_hash, near_payment);
}
_ => {}
}Checking Payment (USD)#
// USD_PAYMENT is in micro-units: 1000000 = $1.00
let usd_payment: u64 = std::env::var("USD_PAYMENT")
.unwrap_or_else(|_| "0".to_string())
.parse()
.unwrap_or(0);
// Require $0.10 minimum for premium features
const MIN_PREMIUM_USD: u64 = 100_000; // $0.10
if usd_payment >= MIN_PREMIUM_USD {
// Premium feature
expensive_ai_analysis();
} else if usd_payment > 0 {
// Basic paid feature
basic_analysis();
} else {
// Free tier
simple_response();
}Error Codes#
| Code | Status | Description |
|---|---|---|
| 400 | Bad Request | Invalid request body or headers |
| 401 | Unauthorized | Invalid or missing Payment Key |
| 402 | Payment Required | Insufficient balance on Payment Key |
| 403 | Forbidden | Project not allowed for this key |
| 404 | Not Found | Project does not exist |
| 429 | Too Many Requests | Rate limit exceeded (IP or key) |
| 500 | Internal Error | Server error during execution |
| 504 | Gateway Timeout | Execution timeout (300s max) |
Code Examples#
cURL#
# Basic call
curl -X POST https://api.outlayer.io/call/alice.near/weather-api \
-H "X-Payment-Key: bob.near:0:K7xR2mN9pQs5vW3yZ8bF..." \
-H "Content-Type: application/json" \
-d '{"input": {"city": "Tokyo"}}'
# With compute limit and author payment
curl -X POST https://api.outlayer.io/call/alice.near/premium-api \
-H "X-Payment-Key: bob.near:0:K7xR2mN9pQs5vW3yZ8bF..." \
-H "X-Compute-Limit: 500000" \
-H "X-Attached-Deposit: 100000" \
-H "Content-Type: application/json" \
-d '{"input": {"query": "complex analysis"}}'
# Async mode
curl -X POST https://api.outlayer.io/call/alice.near/long-running \
-H "X-Payment-Key: bob.near:0:K7xR2mN9pQs5vW3yZ8bF..." \
-H "Content-Type: application/json" \
-d '{"input": {...}, "async": true}'JavaScript / TypeScript#
async function callOutLayer(projectId: string, input: object) {
const response = await fetch(`https://api.outlayer.io/call/${projectId}`, {
method: 'POST',
headers: {
'X-Payment-Key': process.env.OUTLAYER_PAYMENT_KEY!,
'X-Compute-Limit': '100000', // $0.10 max
'X-Attached-Deposit': '50000', // $0.05 to author
'Content-Type': 'application/json',
},
body: JSON.stringify({ input }),
});
if (!response.ok) {
throw new Error(`OutLayer error: ${response.status}`);
}
const result = await response.json();
if (result.status === 'failed') {
throw new Error(`Execution failed: ${result.error}`);
}
const costUsd = Number(result.compute_cost) / 1_000_000;
console.log('Cost:', costUsd, 'USD');
return result.output;
}
// Usage
const weather = await callOutLayer('alice.near/weather-api', { city: 'Tokyo' });Python#
import os
import requests
def call_outlayer(project_id: str, input_data: dict) -> dict:
"""Call an OutLayer project via HTTPS API."""
response = requests.post(
f"https://api.outlayer.io/call/{project_id}",
headers={
"X-Payment-Key": os.environ["OUTLAYER_PAYMENT_KEY"],
"X-Compute-Limit": "100000", # $0.10 max
"X-Attached-Deposit": "50000", # $0.05 to author
"Content-Type": "application/json",
},
json={"input": input_data},
)
response.raise_for_status()
result = response.json()
if result["status"] == "failed":
raise Exception(f"Execution failed: {result['error']}")
cost = int(result['compute_cost']) / 1_000_000
print(f"Cost: {cost} USD")
return result["output"]
# Usage
weather = call_outlayer("alice.near/weather-api", {"city": "Tokyo"})Pricing#
HTTPS API calls are charged in USD stablecoins based on actual resource consumption:
compute_cost = base_fee_usd
+ (instructions / 1M) × per_million_instructions_usd
+ execution_time_ms × per_ms_usd
+ compile_time_ms × per_compile_ms_usd
+ (instructions / 1M) × per_million_instructions_usd
+ execution_time_ms × per_ms_usd
+ compile_time_ms × per_compile_ms_usd
See Pricing & Limits for current rates. Key points:
- compute_cost - charged based on actual resources used
- X-Attached-Deposit - charged immediately, goes to project author
- Minimum: X-Compute-Limit must be at least $0.001 (1000)
- Failures: you still pay for resources used before the failure
Related Documentation
- Payment Keys - Creating and managing Payment Keys
- Earnings - How project authors earn from X-Attached-Deposit
- Web2 Integration - Complete HTTPS integration guide
- TEE Attestation - Verifying execution attestations