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.fastnear.com/call/alice.near/my-assistant \
  -H "X-Payment-Key: bob.near:1:K7xR2mN9pQs5vW3yZ8bF..." \
  -H "Content-Type: application/json" \
  -d '{"input": {"prompt": "Hello!"}}'

Request Format#

Endpoint#

POST https://api.outlayer.fastnear.com/call/{project_owner}/{project_name}

Example: POST https://api.outlayer.fastnear.com/call/alice.near/weather-api

Request Headers#

HeaderRequiredDefaultDescription
X-Payment-KeyYes-Format: owner:nonce:secret
Authentication for the API call
X-Compute-LimitNo10000Max compute budget in USD micro-units
10000 = $0.01, 100000 = $0.10
X-Attached-DepositNo0Payment to project author in USD micro-units
1000000 = $1.00. Goes to author's earnings.
Content-TypeNoapplication/jsonRequest body format

X-Attached-Deposit vs X-Compute-Limit:

  • X-Compute-Limit - pays for infrastructure (OutLayer), refunded if unused
  • X-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
  },
  "secrets_ref": {              // Optional - keystore secrets
    "profile": "default",
    "account_id": "alice.near"
  },
  "async": false,               // Optional - sync (default) or async mode
  "version_key": "user/repo@a1b2c3" // Optional - pin to specific version
}
FieldTypeRequiredDescription
inputobjectYesPassed to WASM code as JSON via stdin
resource_limitsobjectNoOverride project's default limits
secrets_refobjectNoReference to keystore secrets. Contains profile (string) and account_id (string). Decrypted secrets are injected as environment variables into WASM.
asyncbooleanNofalse = wait for result, true = return call_id immediately
version_keystringNoPin to a specific project version. Format: WASM hash or repo@commit. If omitted, uses the project's active version.

Resource Limits#

LimitDefaultMaximumDescription
max_instructions1 billion500 billionWASM instructions to execute
max_memory_mb128 MB512 MBMemory available to WASM
max_execution_seconds60 sec180 secWall-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.fastnear.com/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.fastnear.com/calls/550e8400-e29b-41d4-a716-446655440000"
}

Poll the result using GET /calls/{call_id}:

curl -H "X-Payment-Key: bob.near:1:..." \
  https://api.outlayer.fastnear.com/calls/550e8400-e29b-41d4-a716-446655440000

Response Fields#

FieldTypeDescription
call_idUUIDUnique identifier for this API call
statusstring"pending", "completed", or "failed"
outputanyWASM stdout (only when completed)
errorstringError message (only when failed)
compute_coststringActual USD cost in micro-units (e.g., "45000" = $0.045). Charged even on failure.
job_idnumberInternal job ID for attestation lookup
attestation_urlstringLink 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:

VariableNEARHTTPS
OUTLAYER_EXECUTION_TYPE"NEAR""HTTPS"
NEAR_NETWORK_ID"testnet" or "mainnet""testnet" or "mainnet"
NEAR_SENDER_IDTransaction signerPayment Key owner
USD_PAYMENT"0"X-Attached-Deposit value
NEAR_PAYMENT_YOCTOAttached NEAR"0"
OUTLAYER_CALL_ID""call_id UUID
NEAR_TRANSACTION_HASHTransaction hash""
NEAR_BLOCK_HEIGHTBlock number""
NEAR_BLOCK_TIMESTAMPBlock timestamp""
OUTLAYER_PROJECT_IDowner/name (same for both)
OUTLAYER_PROJECT_OWNERProject owner account (e.g., "alice.near")
OUTLAYER_PROJECT_NAMEProject name (may contain "/")

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();
}

Using Secrets#

If your WASM code needs API keys or other sensitive data, use Keystore Secrets. Secrets are encrypted and stored on-chain, then decrypted inside TEE at execution time and injected as environment variables.

Pass secrets_ref in the request body to specify which secret profile to use:

curl -X POST https://api.outlayer.fastnear.com/call/alice.near/weather-api \
  -H "X-Payment-Key: bob.near:1:K7xR2mN9pQs5vW3yZ8bF..." \
  -H "Content-Type: application/json" \
  -d '{
    "input": {"city": "Tokyo"},
    "secrets_ref": {
      "profile": "default",
      "account_id": "alice.near"
    }
  }'
FieldTypeDescription
profilestringSecret profile name (e.g., "default", "production"). Configured in the Secrets page.
account_idstringNEAR account that owns the secrets (the one who encrypted them)

Accessing Secrets in WASM#

Decrypted secrets are available as regular environment variables:

// Secrets are injected as env vars by the TEE worker
let api_key = std::env::var("OPENAI_API_KEY")
    .expect("OPENAI_API_KEY secret not set");

let db_url = std::env::var("DATABASE_URL")
    .expect("DATABASE_URL secret not set");

Works the same as NEAR transactions. The secrets_ref field uses the same keystore system as the secrets_ref parameter in request_execution contract calls. If your WASM already uses secrets via NEAR transactions, just pass the same profile in HTTPS calls.

Error Codes#

CodeStatusDescription
400Bad RequestInvalid request body or headers
401UnauthorizedInvalid or missing Payment Key
402Payment RequiredInsufficient balance on Payment Key
403ForbiddenProject not allowed for this key
404Not FoundProject does not exist
429Too Many RequestsRate limit exceeded (IP or key)
500Internal ErrorServer error during execution
504Gateway TimeoutExecution timeout (300s max)

Code Examples#

cURL#

# Basic call
curl -X POST https://api.outlayer.fastnear.com/call/alice.near/weather-api \
  -H "X-Payment-Key: bob.near:1:K7xR2mN9pQs5vW3yZ8bF..." \
  -H "Content-Type: application/json" \
  -d '{"input": {"city": "Tokyo"}}'

# With compute limit and author payment
curl -X POST https://api.outlayer.fastnear.com/call/alice.near/premium-api \
  -H "X-Payment-Key: bob.near:1: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.fastnear.com/call/alice.near/long-running \
  -H "X-Payment-Key: bob.near:1: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.fastnear.com/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.fastnear.com/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

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