diff --git a/README.md b/README.md
index 7732a5c..9e08d1b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# ReliAPI
-Reliability layer for API calls: retries, caching, dedup, circuit breakers.
+Beta self-hosted proxy for HTTP and LLM calls with Redis-backed caching,
+non-streaming LLM idempotency, and configurable LLM budget guardrails.
[](https://www.npmjs.com/package/reliapi-sdk)
[](https://pypi.org/project/reliapi-sdk/)
@@ -8,17 +9,20 @@ Reliability layer for API calls: retries, caching, dedup, circuit breakers.
**[Open the project site](https://kikuai-lab.github.io/reliapi/)**
+> [!IMPORTANT]
+> ReliAPI is beta software for evaluation and self-hosting. It does not provide
+> an SLA, managed multi-upstream fallback, exactly-once delivery, quantified
+> savings, or published performance targets.
+
## Features
-- **Retries with Backoff** - Automatic retries with exponential backoff
-- **Circuit Breaker** - Prevent cascading failures
-- **Caching** - TTL cache for GET requests and LLM responses
-- **Idempotency** - Request coalescing with idempotency keys
-- **Rate Limiting** - Built-in rate limiting per tier
-- **LLM Proxy** - Unified interface for OpenAI, Anthropic, Mistral
-- **Cost Control** - Budget caps and cost estimation
-- **Self-Service Onboarding** - Automated API key generation
-- **Paddle Payments** - Subscription management
+- **Caching** - TTL cache for HTTP GET/HEAD and non-streaming LLM responses
+- **Idempotency** - Redis-backed primitives used by the non-streaming LLM path
+- **LLM Proxy** - Configured OpenAI, Anthropic, and Mistral targets
+- **Budget Guardrails** - Pre-request estimates with hard and soft caps
+- **Rate Limiting** - Built-in request limits per configured tier
+- **Experimental Resilience** - Retry and circuit-breaker code remains under
+ beta review and is not part of the documented reliability baseline
## Project Structure
@@ -50,10 +54,14 @@ Try ReliAPI directly on [RapidAPI](https://rapidapi.com/kikuai-lab-kikuai-lab-de
### Self-Hosting with Docker
```bash
-docker run -d -p 8000:8000 \
- -e REDIS_URL="redis://localhost:6379/0" \
- -e RELIAPI_CONFIG_PATH=/app/config.yaml \
- kikudoc/reliapi:latest
+git clone https://github.com/KikuAI-Lab/reliapi.git
+cd reliapi
+cp .env.example .env
+
+# Add the provider key(s) referenced by config.yaml to .env, then start
+# ReliAPI and its Redis service.
+docker compose up -d --build
+curl http://localhost:8000/healthz
```
### Local Development
@@ -109,8 +117,8 @@ targets:
| Endpoint | Method | Description |
|----------|--------|-------------|
-| `/proxy/http` | POST | Proxy any HTTP API with reliability |
-| `/proxy/llm` | POST | Proxy LLM requests with cost control |
+| `/v1/proxy/http` | POST | Proxy a request to a configured HTTP target |
+| `/v1/proxy/llm` | POST | Proxy a request to a configured LLM target |
| `/healthz` | GET | Health check |
| `/metrics` | GET | Prometheus metrics |
@@ -160,7 +168,7 @@ PADDLE_ENVIRONMENT=sandbox
from reliapi_sdk import ReliAPI
client = ReliAPI(
- base_url="https://reliapi.kikuai.dev",
+ base_url="http://localhost:8000",
api_key="your-api-key"
)
@@ -187,7 +195,7 @@ llm_response = client.proxy_llm(
import { ReliAPI } from 'reliapi-sdk';
const client = new ReliAPI({
- baseUrl: 'https://reliapi.kikuai.dev',
+ baseUrl: 'http://localhost:8000',
apiKey: 'your-api-key'
});
@@ -198,6 +206,20 @@ const response = await client.proxyLlm({
});
```
+## Beta Limitations
+
+- Redis must be reachable for shared cache and idempotency behavior.
+- HTTP response caching applies to GET and HEAD; LLM caching applies to the
+ non-streaming path.
+- The documented idempotency baseline covers non-streaming LLM calls. HTTP
+ idempotency and streaming behavior remain under beta review.
+- Idempotency is not a promise of exactly-once upstream execution or provider
+ billing behavior.
+- Budget caps use pre-request estimates, not authoritative invoices or
+ account-wide spending limits.
+- Deployment security, target allow-lists, Redis durability, observability, and
+ provider quotas remain the self-hosting operator's responsibility.
+
## Testing
```bash
@@ -222,7 +244,8 @@ See [`docs/release.md`](./docs/release.md) and [`docs/SECRETS_SETUP.md`](./docs/
- [OpenAPI Spec](./openapi/openapi.yaml)
- [Postman Collection](./postman/collection.json)
-- [Live Docs](https://reliapi.kikuai.dev/docs)
+- [Project Site](https://kikuai-lab.github.io/reliapi/)
+- [Wiki](https://github.com/KikuAI-Lab/reliapi/wiki)
## Support
diff --git a/docs/index.html b/docs/index.html
index c65cb85..14d10a8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -3,128 +3,20 @@
- ReliAPI - Stability Engine for HTTP and LLM APIs
-
-
-
-
-
-
-
-
-
-
-
+ ReliAPI - Beta HTTP and LLM Proxy Primitives
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -338,10 +230,6 @@
.vis-content > div > div { min-width: auto !important; }
.vis-content .flex.flex-col.items-center { min-width: 60px !important; }
.vis-content .flex.flex-col.items-center > div { width: 50px !important; height: 50px !important; font-size: 1.25rem !important; }
- .vis-content .server-card { padding: 0.5rem !important; gap: 0.5rem !important; }
- .vis-content .server-card svg { width: 24px !important; height: 24px !important; }
- .vis-content .server-card .font-medium { font-size: 0.75rem !important; }
- .vis-content .server-card .text-sm { font-size: 0.7rem !important; }
.vis-content .funnel-box { width: 60px !important; height: 60px !important; padding: 0.5rem !important; }
.vis-content .funnel-box svg { width: 32px !important; height: 32px !important; }
.vis-content .funnel-box .text-xs { font-size: 0.65rem !important; }
@@ -349,8 +237,6 @@
.vis-content .text-2xl { font-size: 1.25rem !important; }
.vis-content .text-sm { font-size: 0.75rem !important; }
.code-block { font-size: 0.75rem !important; padding: 1rem !important; }
- .comparison-table { font-size: 0.875rem; }
- .comparison-table th, .comparison-table td { padding: 0.75rem 0.5rem !important; }
.link-card { padding: 1rem !important; }
.link-icon { width: 40px !important; height: 40px !important; }
.btn { padding: 0.75rem 1.5rem !important; font-size: 0.875rem !important; }
@@ -380,10 +266,6 @@
.vis-content .flex.flex-col.items-center { min-width: 50px !important; }
.vis-content .flex.flex-col.items-center > div { width: 40px !important; height: 40px !important; font-size: 1rem !important; }
.vis-content .flex.flex-col.items-center .text-xs { font-size: 0.6rem !important; }
- .vis-content .server-card { padding: 0.4rem !important; gap: 0.4rem !important; }
- .vis-content .server-card svg { width: 20px !important; height: 20px !important; }
- .vis-content .server-card .font-medium { font-size: 0.7rem !important; }
- .vis-content .server-card .text-sm { font-size: 0.65rem !important; }
.vis-content .funnel-box { width: 50px !important; height: 50px !important; padding: 0.4rem !important; }
.vis-content .funnel-box svg { width: 24px !important; height: 24px !important; }
.vis-content .funnel-box .text-xs { font-size: 0.6rem !important; }
@@ -392,8 +274,6 @@
.vis-content .text-sm { font-size: 0.7rem !important; }
.vis-content .flex.flex-col.gap-8 { gap: 0.5rem !important; }
.code-block { font-size: 0.7rem !important; padding: 0.75rem !important; }
- .comparison-table { font-size: 0.75rem; overflow-x: auto; display: block; }
- .comparison-table th, .comparison-table td { padding: 0.5rem 0.25rem !important; white-space: nowrap; }
}
/* Hero Section */
@@ -705,94 +585,6 @@
padding: 2rem;
}
- .server-card {
- display: flex;
- align-items: center;
- gap: 1rem;
- padding: 1rem;
- border-radius: 0.75rem;
- border: 2px solid var(--border);
- background: var(--card);
- transition: all 0.5s ease;
- }
-
- .server-card.error {
- border-color: var(--destructive);
- background: rgba(248, 113, 113, 0.1);
- }
-
- .server-card.success {
- border-color: var(--green);
- background: rgba(74, 222, 128, 0.1);
- box-shadow: 0 0 30px rgba(74, 222, 128, 0.3);
- }
-
- .server-card.activating {
- border-color: var(--primary);
- background: rgba(168, 156, 196, 0.1);
- }
-
- .countdown-circle {
- width: 192px;
- height: 192px;
- border-radius: 50%;
- border: 4px solid var(--border);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
- transition: all 0.5s ease;
- }
-
- .countdown-circle.warning {
- border-color: var(--yellow);
- background: rgba(251, 191, 36, 0.1);
- }
-
- .countdown-circle.processing {
- border-color: var(--primary);
- background: rgba(168, 156, 196, 0.1);
- }
-
- .countdown-circle.success {
- border-color: var(--green);
- background: rgba(74, 222, 128, 0.1);
- box-shadow: 0 0 60px rgba(74, 222, 128, 0.4);
- }
-
- .spinning-ring {
- position: absolute;
- inset: 0;
- border-radius: 50%;
- border: 4px solid transparent;
- border-top-color: var(--primary);
- animation: spin 1s linear infinite;
- }
-
- .retry-box {
- width: 64px;
- height: 64px;
- border-radius: 0.75rem;
- border: 2px solid var(--border);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background: var(--card);
- transition: all 0.3s ease;
- }
-
- .retry-box.active {
- border-color: var(--primary);
- background: rgba(168, 156, 196, 0.2);
- }
-
- .retry-box.success {
- border-color: var(--green);
- background: rgba(74, 222, 128, 0.2);
- }
-
.funnel-box {
width: 128px;
height: 128px;
@@ -844,127 +636,6 @@
font-weight: 600;
}
- /* Statistics Section */
- .stat-card {
- padding: 1rem;
- border-radius: 0.75rem;
- border: 1px solid var(--border);
- background: rgba(40, 47, 51, 0.5);
- cursor: pointer;
- transition: all 0.3s ease;
- }
-
- .stat-card:hover {
- border-color: var(--primary);
- background: rgba(168, 156, 196, 0.1);
- transform: scale(1.05);
- box-shadow: 0 0 30px rgba(168, 156, 196, 0.2);
- }
-
- .progress-bar {
- height: 12px;
- background: var(--card);
- border-radius: 9999px;
- overflow: hidden;
- }
-
- .progress-fill {
- height: 100%;
- border-radius: 9999px;
- transition: width 1s ease-out;
- }
-
- .progress-fill.red { background: rgba(248, 113, 113, 0.8); }
- .progress-fill.green { background: rgba(74, 222, 128, 0.8); }
-
- .latency-bar {
- height: 40px;
- background: var(--card);
- border-radius: 0.5rem;
- overflow: hidden;
- cursor: pointer;
- transition: all 0.3s ease;
- }
-
- .latency-bar:hover {
- transform: scale(1.05);
- box-shadow: 0 0 20px rgba(168, 156, 196, 0.3);
- }
-
- .latency-fill {
- height: 100%;
- border-radius: 0.5rem;
- transition: width 1s ease-out;
- display: flex;
- align-items: center;
- padding-left: 0.75rem;
- }
-
- /* Comparison Table */
- .comparison-table {
- width: 100%;
- border-collapse: collapse;
- border-radius: 1rem;
- overflow: hidden;
- }
-
- .comparison-table th,
- .comparison-table td {
- padding: 1.25rem 1rem;
- text-align: center;
- }
-
- .comparison-table th {
- background: transparent;
- border-bottom: 1px solid var(--border);
- font-weight: 500;
- color: var(--muted-foreground);
- }
-
- .comparison-table th.highlight {
- color: var(--primary);
- font-weight: 700;
- font-size: 1.125rem;
- }
-
- .comparison-table tbody tr {
- border-bottom: 1px solid rgba(58, 66, 72, 0.5);
- transition: all 0.3s ease;
- }
-
- .comparison-table tbody tr:hover {
- background: rgba(168, 156, 196, 0.05);
- }
-
- .comparison-table td:first-child {
- text-align: left;
- padding-left: 1.5rem;
- }
-
- .status-icon {
- width: 32px;
- height: 32px;
- border-radius: 50%;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- }
-
- .status-icon.full {
- background: rgba(74, 222, 128, 0.2);
- color: var(--green);
- }
-
- .status-icon.partial {
- background: rgba(251, 191, 36, 0.2);
- color: var(--yellow);
- }
-
- .status-icon.none {
- background: rgba(248, 113, 113, 0.2);
- color: var(--destructive);
- }
-
/* Code Examples */
.code-tabs {
display: flex;
@@ -1160,9 +831,10 @@
+ Beta ยท Self-hosted
ReliAPI
- Stability Engine for HTTP and LLM APIs
+ Caching, non-streaming LLM idempotency, and budget guardrails
-
-
@@ -1188,20 +854,15 @@
ReliAPI
-
+
-
- Transform
- Chaos
- into
- Stability
-
+
Self-hosted Proxy Primitives for Evaluation
-
Chaos
+
Requests
@@ -1261,7 +922,7 @@
-
Stability
+
Responses
@@ -1274,31 +935,16 @@
See ReliAPI in Action
-
Click a scenario to see how it works
+
Click a scenario to see an illustrative beta flow
+
These flows cover the documented non-streaming LLM and budget baseline; review the Beta Limitations before integrating.
-
@@ -1324,193 +970,6 @@
See ReliAPI in Action
-
-
-
-
Performance That Speaks for Itself
-
Hover over metrics to explore the ReliAPI difference
-
*Benchmarks are synthetic. Actual results depend on environment. See methodology
-
-
-
-
-
Direct API vs With ReliAPI
-
-
-
-
-
-
P95 Proxy Overhead (ms)
-
Additional latency added by proxy layer
-
-
-
- Helicone
- ~40ms
-
-
-
-
-
- LiteLLM
- ~30ms
-
-
-
-
-
- Portkey
- ~25ms
-
-
-
-
-
- ReliAPI
- ~15ms
-
-
-
-
-
-
-
-
-
-
-
-
-
How We Compare
-
Feature comparison with popular alternatives
-
-
-
-
-
- | Feature |
- ReliAPI |
- LiteLLM |
- Portkey |
- Helicone |
-
-
-
-
- | Self-hosted Option |
- โ |
- โ |
- โ |
- โ |
-
-
- | HTTP + LLM Support |
- โ |
- โ |
- โ |
- โ |
-
-
- | Idempotency Keys |
- โ |
- โ |
- ~ |
- โ |
-
-
- | Budget Caps |
- โ |
- ~ |
- โ |
- ~ |
-
-
- | Minimal Config |
- โ |
- ~ |
- ~ |
- โ |
-
-
- | Streaming Support |
- โ |
- โ |
- โ |
- โ |
-
-
-
-
-
-
-
@@ -1547,7 +1006,7 @@
Get Started Today
Try on RapidAPI
-
Start using ReliAPI in minutes
+
Open the current API listing
@@ -1557,7 +1016,7 @@ Get Started Today
Documentation
-
Complete API reference
+
Project documentation
@@ -1571,16 +1030,9 @@ Get Started Today
-
-
-
@@ -1630,166 +1082,6 @@ Get Started Today
let animationTimeout = null;
const scenarios = {
- 'provider-errors': {
- chaos: `
-
-
-
-
- ๐จ
-
-
Your Request
-
-
โ
-
-
-
-
-
Primary Server
-
โ Error 500!
-
-
-
-
-
-
Backup Server
-
Standby
-
-
-
-
โ
-
-
-
- `,
- processing: `
-
-
-
-
- ๐จ
-
-
Your Request
-
-
โ
-
-
-
-
-
Primary Server
-
Offline
-
-
-
-
-
-
Backup Server
-
๐ Activating...
-
-
-
-
โ
-
-
-
- `,
- resolved: `
-
-
-
-
- ๐จ
-
-
Your Request
-
-
โ
-
-
-
-
-
Primary Server
-
Offline
-
-
-
-
-
-
Backup Server
-
โ
Online!
-
-
-
-
-
โ
-
-
-
- `
- },
- 'rate-limits': {
- chaos: `
-
-
-
-
-
429
-
Rate Limited!
-
-
-
-
- `,
- processing: `
-
- `,
- resolved: `
-
- `
- },
'request-storm': {
chaos: `
@@ -1801,8 +1093,8 @@
Get Started Today
`).join('')}
-
8
-
requests
+
N
+
same-key calls
โ
@@ -1825,8 +1117,8 @@ Get Started Today
-
8
-
requests
+
N
+
same-key calls
โ
@@ -1849,8 +1141,8 @@
Get Started Today
-
8
-
requests
+
N
+
same-key calls
โ
@@ -1863,7 +1155,7 @@
Get Started Today
-
request
+
upstream owner
@@ -1876,17 +1168,17 @@ Get Started Today
-
$150.00
-
Current spending
+
Estimate
+
Above configured cap
-
Budget: $100
+
Hard cap
- โ ๏ธ Budget exceeded by $50!
+ โ ๏ธ Estimate exceeds the hard cap
`,
@@ -1896,17 +1188,17 @@ Get Started Today
-
Analyzing...
-
Applying budget protection
+
Evaluating...
+
Applying configured policy
-
Budget: $100
+
Configured cap
- ๐ก๏ธ ReliAPI protecting your budget...
+ Checking the estimate before the provider call...
`,
@@ -1916,17 +1208,17 @@ Get Started Today
-
$99.50
-
Budget protected!
+
Rejected
+
Provider call not started
-
Budget: $100 โ
+
Hard cap โ
- โ
Saved $50.50 by caching & deduplication!
+ Hard-cap rejection is returned in response metadata
`
@@ -1967,7 +1259,7 @@ Get Started Today
visualization.className = 'visualization-area processing';
visContent.innerHTML = scenarios[scenario].processing;
phaseBadge.className = 'phase-badge processing';
- phaseBadge.innerHTML = ' ReliAPI handling it';
+ phaseBadge.innerHTML = ' Illustrative flow';
}, 2000);
// Resolved phase
@@ -1975,7 +1267,7 @@ Get Started Today
visualization.className = 'visualization-area resolved';
visContent.innerHTML = scenarios[scenario].resolved;
phaseBadge.className = 'phase-badge resolved';
- phaseBadge.innerHTML = ' Problem solved';
+ phaseBadge.innerHTML = ' Illustration complete';
}, 4000);
}
@@ -1983,15 +1275,14 @@ Get Started Today
btn.addEventListener('click', () => runScenario(btn.dataset.scenario));
});
- // Auto-activate Provider Errors when section comes into view
+ // Auto-activate the LLM idempotency example when the section comes into view
const featuresSection = document.querySelector('.section.section-bg');
const featuresObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !activeScenario) {
- // Auto-activate Provider Errors scenario
- const providerErrorsBtn = document.querySelector('[data-scenario="provider-errors"]');
- if (providerErrorsBtn) {
- runScenario('provider-errors');
+ const idempotencyBtn = document.querySelector('[data-scenario="request-storm"]');
+ if (idempotencyBtn) {
+ runScenario('request-storm');
}
// Unobserve after activation
featuresObserver.unobserve(entry.target);
@@ -2003,55 +1294,25 @@ Get Started Today
featuresObserver.observe(featuresSection);
}
- // Animate stats on scroll
- const statsObserver = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- document.getElementById('stat-error-direct').style.width = '20%';
- document.getElementById('stat-error-reli').style.width = '1%';
- document.getElementById('stat-cost-direct').style.width = '30%';
- document.getElementById('stat-cost-reli').style.width = '2%';
- document.getElementById('stat-cache-direct').style.width = '15%';
- document.getElementById('stat-cache-reli').style.width = '68%';
-
- setTimeout(() => {
- document.getElementById('latency-helicone').style.width = '100%';
- }, 500);
- setTimeout(() => {
- document.getElementById('latency-litellm').style.width = '75%';
- }, 650);
- setTimeout(() => {
- document.getElementById('latency-portkey').style.width = '62%';
- }, 800);
- setTimeout(() => {
- document.getElementById('latency-reliapi').style.width = '37%';
- }, 950);
- }
- });
- }, { threshold: 0.2 });
-
- document.querySelectorAll('.stat-card').forEach(card => statsObserver.observe(card));
- document.querySelectorAll('.latency-bar').forEach(bar => statsObserver.observe(bar));
-
// Code Examples
const codeExamples = {
python: `import requests
response = requests.post(
- "https://reliapi.kikuai.dev/proxy/llm",
+ "http://localhost:8000/v1/proxy/llm",
headers={
"X-API-Key": "YOUR_API_KEY",
"X-Idempotency-Key": "unique-request-id"
},
json={
"target": "openai",
- "model": "gpt-4",
+ "model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}]
}
)
print(response.json())`,
- javascript: `const response = await fetch("https://reliapi.kikuai.dev/proxy/llm", {
+ javascript: `const response = await fetch("http://localhost:8000/v1/proxy/llm", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
@@ -2060,20 +1321,20 @@ Get Started Today
},
body: JSON.stringify({
target: "openai",
- model: "gpt-4",
+ model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }]
})
});
const data = await response.json();
console.log(data);`,
- curl: `curl -X POST https://reliapi.kikuai.dev/proxy/llm \\
+ curl: `curl -X POST http://localhost:8000/v1/proxy/llm \\
-H "X-API-Key: YOUR_API_KEY" \\
-H "X-Idempotency-Key: unique-request-id" \\
-H "Content-Type: application/json" \\
-d '{
"target": "openai",
- "model": "gpt-4",
+ "model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}]
}'`
};
diff --git a/pyproject.toml b/pyproject.toml
index 9c07bb0..dde2f9d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -44,7 +44,7 @@ dev = [
[project.urls]
"Homepage" = "https://github.com/KikuAI-Lab/reliapi"
-"Documentation" = "https://reliapi.kikuai.dev"
+"Documentation" = "https://kikuai-lab.github.io/reliapi/"
"Bug Tracker" = "https://github.com/KikuAI-Lab/reliapi/issues"
[tool.setuptools.packages.find]