Authentication
Every request to the Oris API requires authentication. Sandbox calls need an API key. Production calls require an API key plus Ed25519 request signing.
API Key Authentication
All requests must include your API key in the Authorization header. Keys follow the format oris_sk_live_ for production and oris_sk_test_ for sandbox.
Generate keys from API Keys in the developer dashboard. Each key is scoped to a single environment. Production keys cannot access sandbox data, and sandbox keys cannot access production data.
Ed25519 Request Signing
Production requests must include an Ed25519 signature for tamper protection. The server validates the signature before processing the request. Sandbox requests skip signature validation.
Include these headers alongside the Authorization header:
-
X-Request-Signature-- Ed25519 signature (128 hex chars) of the canonical string -
X-Timestamp-- Unix epoch in seconds. Must be within 30 seconds of server time. -
X-Nonce-- Unique token per request. The server rejects duplicate nonces within 30 seconds.
Signing Algorithm
Build the canonical string by concatenating these five components with dot separators:
X-Timestamp)
X-Nonce)
POST)
/api/v1/oris/agents)
Canonical format: {timestamp}.{nonce}.{METHOD}.{path}.{SHA256(body)}
Sign the canonical string with your Ed25519 private key. Send the resulting hex digest as X-Request-Signature.
Code Example
A complete Python example that signs and sends a request:
# Python SDK handles signing automatically
from oris import OrisClient
client = OrisClient(
api_key="oris_sk_live_your_key_here",
api_secret="oris_pk_live_your_private_key",
)
# SDK signs all requests automatically
agents = client.agents.list()
# Manual signing (direct HTTP)
import hashlib, time, uuid, json
from nacl.signing import SigningKey
api_key = "oris_sk_live_..."
private_key = SigningKey(bytes.fromhex("..."))
method = "POST"
path = "/api/v1/oris/agents"
body = json.dumps({"name": "payment-bot"})
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4())
body_hash = hashlib.sha256(body.encode()).hexdigest()
canonical = f"{timestamp}.{nonce}.{method}.{path}.{body_hash}"
signature = private_key.sign(canonical.encode()).signature.hex()
The Python and TypeScript SDKs handle signing automatically. Manual signing is only required for direct HTTP calls.
Rate Limits
Rate limits apply per API key. The server returns a 429 status code when the limit is exceeded. The Retry-After header indicates how many seconds to wait before retrying.
| Plan | Limit | Window |
|---|---|---|
| Sandbox | 1,000 calls | Per day |
| Growth | 1,000 calls | Per minute |
| Enterprise | Custom | Custom |
Error Codes
Authentication failures return one of these HTTP status codes with a JSON error body:
| Code | Meaning | Action |
|---|---|---|
401 | Invalid or missing API key | Check the Authorization header value |
403 | Signature mismatch | Verify the canonical string construction and private key |
429 | Rate limit exceeded | Wait for the duration in the Retry-After header |