Power Your Legal AI Platform
Integrate the Moonlit Data API as the legal knowledge layer for your commercial legal AI product.
What you'll build
If you are building a legal AI product -- whether it is a contract analysis tool, a compliance platform, a legal research application, or an AI assistant for lawyers -- the Moonlit API provides the comprehensive European legal data layer your product needs. Instead of building and maintaining your own legal data infrastructure (scraping court databases, parsing legislation, building search indices, handling multi-jurisdictional data models), you can use the Moonlit API as your production backend. We handle data ingestion from 50+ European legal sources, maintain search indices with semantic embeddings, and provide structured document retrieval with AI-generated summaries. This guide covers the architecture patterns, scaling considerations, and reliability strategies for using the Moonlit API as a commercial data provider. Contact us for enterprise pricing, SLAs, and dedicated support.
Architecture
┌───────────────────────────────────────────────────┐
│ Your Legal AI Product │
│ ┌──────────┐ ┌────────────┐ ┌───────────────┐ │
│ │ Frontend │ │ Your │ │ Your AI / │ │
│ │ │ │ Backend │ │ LLM Layer │ │
│ └──────────┘ └──────┬─────┘ └───────────────┘ │
└───────────────────────┼───────────────────────────┘
│
▼
┌───────────────────────────────────────────────────┐
│ Moonlit Data API │
│ Search | Filters | Documents | Luna AI │
│ 50+ EU Sources | Semantic Embeddings | AI Summaries │
└───────────────────────────────────────────────────┘Prerequisites
- An existing legal AI product or product concept
- A backend that can make server-side API calls
- Contact sales@moonlit.ai for enterprise API access
Step-by-step
Choose your architecture pattern
The recommended approach is a proxy pattern: route all Moonlit requests through your backend. This gives you full control over caching, access control, and usage tracking. Never expose the Moonlit API key to your frontend.
// Your backend proxies Moonlit API calls
// Adds caching, auth, logging, and usage tracking
import { Redis } from "ioredis";
const redis = new Redis();
const CACHE_TTL = 3600; // 1 hour
export async function searchLegal(params: Record<string, unknown>) {
const cacheKey = `moonlit:search:${JSON.stringify(params)}`;
// Check cache first
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Forward to Moonlit
const response = await fetch(
"https://api.moonlit.ai/v1.1/search/hybrid_search_reranked",
{
method: "POST",
headers: {
"Ocp-Apim-Subscription-Key": process.env.MOONLIT_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify(params),
},
);
const data = await response.json();
await redis.setex(cacheKey, CACHE_TTL, JSON.stringify(data));
return data;
}Implement tiered caching
Cache filter endpoints aggressively (they change infrequently), cache search results with shorter TTLs, and cache retrieved documents for the longest duration.
const CACHE_TIERS = {
filters: 86400, // 24 hours -- jurisdictions, doc types change rarely
search: 1800, // 30 min -- results change as new docs are ingested
documents: 604800, // 7 days -- individual documents rarely change
};
// Prefetch filters on startup to warm the cache
async function warmFilterCache() {
const endpoints = [
"/search/filters/documenttypes",
"/search/filters/jurisdictions_portals",
"/search/filters/trees",
"/search/semantic_portals",
];
await Promise.all(
endpoints.map(async (path) => {
const res = await fetch(`https://api.moonlit.ai/v1.1${path}`, {
headers: { "Ocp-Apim-Subscription-Key": process.env.MOONLIT_API_KEY! },
});
const data = await res.json();
await redis.setex(`moonlit:${path}`, CACHE_TIERS.filters, JSON.stringify(data));
}),
);
}Add resilience with retry and circuit breaker
Implement exponential backoff for transient errors and a circuit breaker pattern to gracefully degrade when the API is temporarily unavailable.
class MoonlitClient {
private failureCount = 0;
private circuitOpen = false;
private lastFailure = 0;
async request(path: string, options: RequestInit = {}) {
// Circuit breaker: skip requests if too many recent failures
if (this.circuitOpen) {
if (Date.now() - this.lastFailure > 30000) {
this.circuitOpen = false; // Try again after 30s cooldown
} else {
throw new Error("Circuit open -- Moonlit API temporarily unavailable");
}
}
for (let attempt = 0; attempt < 3; attempt++) {
try {
const res = await fetch(`https://api.moonlit.ai/v1.1${path}`, {
...options,
headers: {
"Ocp-Apim-Subscription-Key": process.env.MOONLIT_API_KEY!,
...options.headers,
},
});
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") || "5");
await new Promise((r) => setTimeout(r, retryAfter * 1000));
continue;
}
if (!res.ok) throw new Error(`API error: ${res.status}`);
this.failureCount = 0;
return res.json();
} catch (err) {
this.failureCount++;
if (this.failureCount >= 5) {
this.circuitOpen = true;
this.lastFailure = Date.now();
}
if (attempt === 2) throw err;
await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 1000));
}
}
}
}Contact us for enterprise terms
For production integrations, we offer enterprise plans with higher rate limits, guaranteed SLAs, dedicated support, bulk data access, and custom data licensing terms. Email sales@moonlit.ai or use the contact form on our website to discuss your requirements.