š Overview
Query 1.18M pre-analyzed lunar landing sites across the lunar south pole with intelligent mission planning support.
1.18M
Analyzed Sites
60+
Features per Site
<100ms
Query Response
99.98%
Data Completeness
Base URL: https://lunarlandingsiteapi.up.railway.app
API Version: 1.0.0
Status: Public Beta
š Quick Start
Step 1: Get API Access
- Sign up at ldp-api-beta.vercel.app for free beta access
- Check your email for your API key (starts with
ldp_live_...)
- Make your first request using the examples below
Step 2: Your First Query (30 seconds)
Get intelligent landing site recommendations near the lunar south pole:
Python
import requests
API_KEY = "ldp_live_YOUR_KEY_HERE"
headers = {"X-API-Key": API_KEY}
response = requests.get(
"https://lunarlandingsiteapi.up.railway.app/api/v1/recommendations",
headers=headers,
params={
"lat": -89.5,
"lon": 45,
"mission_type": "artemis",
"top_n": 5
}
)
data = response.json()
print(data["recommendations"][0]["reasoning"])
print(f"Requests remaining: {data['user']['requests_remaining']}")
JavaScript
const API_KEY = "ldp_live_YOUR_KEY_HERE";
const response = await fetch(
'https://lunarlandingsiteapi.up.railway.app/api/v1/recommendations?lat=-89.5&lon=45&mission_type=artemis&top_n=5',
{ headers: { 'X-API-Key': API_KEY } }
);
const data = await response.json();
console.log(data.recommendations[0].reasoning);
console.log(`Requests remaining: ${data.user.requests_remaining}`);
cURL
curl -H "X-API-Key: ldp_live_YOUR_KEY_HERE" \
"https://lunarlandingsiteapi.up.railway.app/api/v1/recommendations?lat=-89.5&lon=45&mission_type=artemis&top_n=5"
š Data Overview
This API provides access to 1.18M pre-analyzed landing sites across the lunar south pole, derived from authoritative NASA datasets:
- Terrain Data: NASA LOLA (Lunar Orbiter Laser Altimeter) at 5m resolution
- Illumination Data: NASA LROC (Lunar Reconnaissance Orbiter Camera)
- Coverage: -90° to -83.5° latitude (lunar south pole region)
- Data Quality: 99.98% completeness (1,179,905 sites with full data)
Each site includes 60+ features analyzed at multiple radii up to 100m radius: terrain metrics (slope, roughness, hazard index), illumination patterns (visibility percentage over lunar year), and data quality indicators.
ā
Why Trust This Data?
- Built on NASA Planetary Data System (PDS) archives
- Research-grade processing pipeline with PostGIS spatial analysis
- Validated against published lunar science literature
- Same data sources used by Artemis mission planning teams
š Authentication
Most endpoints require an API key in the X-API-Key header:
X-API-Key: ldp_live_YOUR_KEY_HERE
Public Endpoints (No Authentication)
These endpoints are accessible without an API key:
| Endpoint |
Purpose |
GET / |
API welcome and endpoint listing |
GET /health |
Health check and database status |
GET /docs |
Interactive Swagger documentation |
GET /openapi.json |
OpenAPI specification |
Protected Endpoints (Authentication Required)
All data and decision support endpoints require a valid API key:
| Endpoint |
Purpose |
GET /api/v1/sites/search |
Search for landing sites (optional auth for full results) |
POST /api/v1/sites/batch |
Bulk site retrieval |
GET /api/v1/recommendations |
Get AI-powered recommendations |
POST /api/v1/compare |
Compare multiple sites |
API Key Management
Where to Find Your Key:
Check the welcome email: "Welcome to Lunar Landing API - Your Access Details"
Key format: ldp_live_ followed by 32 alphanumeric characters
ā ļø Security Best Practices:
- Never share your API key publicly (GitHub, forums, etc.)
- Never commit keys to version control
- Use environment variables:
API_KEY = os.getenv("LUNAR_API_KEY")
- Rotate keys if accidentally exposed
Lost Your Key?
1. Check your email inbox and spam folder
2. Search for emails from Lunar Landing Site API
3. Contact support:
info@irisdatalabs.com
š Rate Limits & Usage
Current Limits
| Tier |
Daily Limit |
Status |
| Beta |
100 requests/day |
Free during beta period |
| Premium |
Coming soon |
Coming soon |
Monitor Your Usage
Every authenticated API response includes your current usage statistics:
{
"user": {
"email": "your.email@example.com",
"name": "Your Name",
"tier": "beta",
"requests_today": 45,
"requests_remaining": 55,
"rate_limit": 100
},
"recommendations": [...]
}
Usage Monitoring Best Practice
data = response.json()
remaining = data['user']['requests_remaining']
if remaining < 100:
print(f"ā ļø Warning: Only {remaining} requests remaining today!")
ā ļø Error Handling
HTTP Status Codes
| Code |
Meaning |
Description |
| 200 |
Success |
Request completed successfully |
| 400 |
Bad Request |
Invalid parameters |
| 401 |
Unauthorized |
Missing API key |
| 403 |
Forbidden |
Invalid or inactive API key |
| 404 |
Not Found |
Resource doesn't exist |
| 422 |
Validation Error |
Parameter validation failed |
| 429 |
Too Many Requests |
Rate limit exceeded |
| 500 |
Server Error |
Internal server error |
| 503 |
Service Unavailable |
Database connection failed |
Error Response Format
{
"detail": {
"error": "Invalid API key",
"message": "The provided API key is not valid or has been deactivated",
"help": "Sign up at https://ldp-api-beta.vercel.app to get a valid API key"
}
}
Common Errors & Solutions
| Error |
Cause |
Solution |
| Missing API key |
No X-API-Key header |
Add header to your request |
| Invalid API key |
Key doesn't exist or is inactive |
Check welcome email for correct key |
| Rate limit exceeded |
100 requests/day limit hit |
Wait until tomorrow (resets at midnight UTC) |
| Invalid parameters |
Coordinates out of range |
Verify lat (-90 to 90), lon (-180 to 180) |
| Site not found |
Invalid site_id |
Use /search to find valid site IDs |
Graceful Error Handling Example
import requests
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
print("ā Missing API key!")
elif e.response.status_code == 403:
print("ā Invalid API key!")
elif e.response.status_code == 429:
print("ā ļø Rate limit exceeded - try again tomorrow")
else:
print(f"Error {e.response.status_code}: {e.response.text}")
except Exception as e:
print(f"Request failed: {str(e)}")
š Endpoints Overview
Status Endpoints
GET / - API information and endpoint listing
GET /health - Health check and database status
Data Endpoints
GET /api/v1/sites/search - Radius-based site search with filters
POST /api/v1/sites/batch - Bulk site retrieval by IDs
Decision Support Endpoints
GET /api/v1/recommendations - Mission-specific intelligent recommendations
POST /api/v1/compare - Side-by-side site comparison
GET /api/v1/sites/search
Description: Search for landing sites within a radius of target coordinates
Authentication: Optional (limited to 10 results without API key, 100 with key)
Parameters
| Parameter |
Type |
Required |
Default |
Range |
Description |
lat |
float |
ā
|
- |
-90 to 90 |
Target latitude |
lon |
float |
ā
|
- |
-180 to 180 |
Target longitude |
radius_m |
int |
ā |
50000 |
1000-500000 |
Search radius in meters |
limit |
int |
ā |
100 |
1-100 |
Max results |
min_visibility |
float |
ā |
- |
0-100 |
Minimum visibility % filter |
max_hazard |
float |
ā |
- |
0-3 |
Maximum hazard index filter |
max_slope |
float |
ā |
- |
0-90 |
Maximum slope filter (degrees) |
Example Request
curl -H "X-API-Key: ldp_live_YOUR_KEY" \
"https://lunarlandingsiteapi.up.railway.app/api/v1/sites/search?lat=-89.5&lon=45.0&radius_m=50000&max_hazard=1.5&limit=10"
Python Example
import requests
API_KEY = "ldp_live_YOUR_KEY_HERE"
headers = {"X-API-Key": API_KEY}
response = requests.get(
"https://lunarlandingsiteapi.up.railway.app/api/v1/sites/search",
headers=headers,
params={
"lat": -89.5,
"lon": 45.0,
"radius_m": 50000,
"max_hazard": 1.5,
"min_visibility": 70.0,
"limit": 10
}
)
data = response.json()
print(f"Found {data['results_found']} sites")
for site in data['sites']:
print(f"Site {site['site_id']}: Hazard {site['terrain_100m']['hazard_index']:.2f}")
Response Example
{
"query": {
"location": {"lat": -89.5, "lon": 45.0},
"search_radius_m": 50000,
"filters": {
"max_hazard": 1.5,
"min_visibility": 70.0
}
},
"results_found": 10,
"sites": [
{
"site_id": 928913,
"location": {"lat": -89.947, "lon": 51.466},
"distance_m": 5012.3,
"terrain_100m": {
"slope_mean_deg": 16.5,
"slope_max_deg": 32.6,
"hazard_index": 3.0,
"roughness_rms_m": 9.73
},
"illumination_100m": {
"visibility_pct": 75.2
}
}
]
}
GET /api/v1/recommendations
Description: Get AI-powered landing site recommendations with mission-specific scoring and plain English reasoning
Authentication: Required
Parameters
| Parameter |
Type |
Required |
Default |
Options |
Description |
lat |
float |
ā
|
- |
-90 to 90 |
Target latitude |
lon |
float |
ā
|
- |
-180 to 180 |
Target longitude |
mission_type |
string |
ā |
artemis |
artemis, robotic, rover, custom |
Mission profile |
radius_m |
int |
ā |
50000 |
10000-500000 |
Search radius in meters |
top_n |
int |
ā |
5 |
1-20 |
Number of recommendations |
Mission Types
| Type |
Description |
Priorities |
artemis |
Human landing mission - prioritizes crew safety |
50% safety, 30% illumination, 20% proximity |
robotic |
Robotic lander - balances safety and power |
40% safety, 40% illumination, 20% proximity |
rover |
Rover traverse - prioritizes accessibility |
30% safety, 20% illumination, 50% accessibility |
custom |
Balanced multi-criteria profile |
40% safety, 30% illumination, 30% proximity |
Example Request
curl -H "X-API-Key: ldp_live_YOUR_KEY" \
"https://lunarlandingsiteapi.up.railway.app/api/v1/recommendations?lat=-89.5&lon=45.0&mission_type=artemis&top_n=5"
Python Example
import requests
API_KEY = "ldp_live_YOUR_KEY_HERE"
headers = {"X-API-Key": API_KEY}
response = requests.get(
"https://lunarlandingsiteapi.up.railway.app/api/v1/recommendations",
headers=headers,
params={
"lat": -89.5,
"lon": 45.0,
"mission_type": "artemis",
"top_n": 5
}
)
data = response.json()
print(f"Mission: {data['mission_profile']['description']}")
print(f"\nTop {len(data['recommendations'])} Recommendations:")
for rec in data['recommendations']:
print(f"\n{rec['rank']}. Site {rec['site_id']} (Score: {rec['overall_score']:.1f}/10)")
print(f" {rec['reasoning']}")
print(f" Strengths: {', '.join(rec['strengths'])}")
if rec['warnings']:
print(f" Warnings: {', '.join(rec['warnings'])}")
Response Example
{
"mission_profile": {
"type": "artemis",
"description": "Artemis human landing mission - prioritizes crew safety",
"priorities": {
"safety": 0.5,
"illumination": 0.3,
"proximity": 0.2
}
},
"recommendations": [
{
"rank": 1,
"site_id": 928913,
"location": {"lat": -89.947, "lon": 51.466},
"overall_score": 4.646,
"reasoning": "Moderate safety concerns with good visibility (75.2%)...",
"warnings": ["Steep slopes present (mean 16.5°)"],
"strengths": ["Meets baseline mission requirements"]
}
]
}
POST /api/v1/compare
Description: Compare multiple landing sites side-by-side with trade-off analysis
Authentication: Required
Limits: Minimum 2 sites, maximum 10 sites
Request Body
{
"site_ids": [928913, 928914, 929072]
}
Example Request
curl -X POST https://lunarlandingsiteapi.up.railway.app/api/v1/compare \
-H "X-API-Key: ldp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"site_ids": [928913, 928914, 929072]}'
Python Example
import requests
API_KEY = "ldp_live_YOUR_KEY_HERE"
headers = {"X-API-Key": API_KEY}
response = requests.post(
"https://lunarlandingsiteapi.up.railway.app/api/v1/compare",
headers=headers,
json={"site_ids": [928913, 928914, 929072]}
)
data = response.json()
print(f"Overall Winner: Site {data['winner_by_category']['overall']}")
print(f"Safest: Site {data['winner_by_category']['safety']}")
print(f"Best Illumination: Site {data['winner_by_category']['illumination']}")
print(f"\nRecommendation: {data['recommendation']['reasoning']}")
Use Cases
- Compare 3-5 finalist sites after initial screening
- Understand trade-offs between safety, illumination, and accessibility
- Get clear recommendation with reasoning
- See category winners (best safety, best illumination, etc.)
š» Complete Code Examples
Python: Complete Mission Planning Workflow
import requests
import json
API_KEY = "ldp_live_YOUR_KEY_HERE"
BASE_URL = "https://lunarlandingsiteapi.up.railway.app"
headers = {"X-API-Key": API_KEY}
def complete_mission_planning_workflow():
"""Complete workflow: Search ā Recommend ā Compare ā Select"""
target_lat, target_lon = -89.5, 45.0
# Step 1: Get initial recommendations
print("Step 1: Getting recommendations near target...")
recs_response = requests.get(
f"{BASE_URL}/api/v1/recommendations",
headers=headers,
params={
"lat": target_lat,
"lon": target_lon,
"mission_type": "artemis",
"top_n": 5
}
)
recs = recs_response.json()
print(f"Found {len(recs['recommendations'])} recommendations")
print(f"Requests remaining: {recs['user']['requests_remaining']}\n")
# Step 2: Print top recommendations
print("Step 2: Top 5 Sites:")
for rec in recs['recommendations']:
print(f"\n{rec['rank']}. Site {rec['site_id']} - Score: {rec['overall_score']:.1f}/10")
print(f" {rec['reasoning']}")
# Step 3: Compare top 3 candidates
print("\n\nStep 3: Comparing top 3 finalists...")
top_3_ids = [rec['site_id'] for rec in recs['recommendations'][:3]]
compare_response = requests.post(
f"{BASE_URL}/api/v1/compare",
headers=headers,
json={"site_ids": top_3_ids}
)
comparison = compare_response.json()
print(f"\nWinner: Site {comparison['winner_by_category']['overall']}")
print(f"Recommendation: {comparison['recommendation']['reasoning']}")
# Save results
with open('mission_planning_results.json', 'w') as f:
json.dump({"recommendations": recs, "comparison": comparison}, f, indent=2)
print(f"\nā
Complete! Results saved.")
if __name__ == "__main__":
complete_mission_planning_workflow()
JavaScript: React Site Search Component
import React, { useState } from 'react';
const API_KEY = "ldp_live_YOUR_KEY_HERE";
const BASE_URL = "https://lunarlandingsiteapi.up.railway.app";
function LunarSiteExplorer() {
const [sites, setSites] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const searchSites = async (lat, lon, missionType = 'artemis') => {
setLoading(true);
setError(null);
try {
const params = new URLSearchParams({
lat, lon, mission_type: missionType, top_n: 5
});
const response = await fetch(
`${BASE_URL}/api/v1/recommendations?${params}`,
{ headers: { 'X-API-Key': API_KEY } }
);
if (!response.ok) throw new Error(`API Error: ${response.status}`);
const data = await response.json();
setSites(data.recommendations);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<div className="lunar-explorer">
<h2>Lunar Landing Site Explorer</h2>
<button onClick={() => searchSites(-89.5, 0, 'artemis')}>
Search Near South Pole
</button>
{loading && <p>Searching...</p>}
{error && <p style={{color: 'red'}}>Error: {error}</p>}
{sites.map(site => (
<div key={site.site_id}>
<h3>Rank {site.rank}: Site {site.site_id}</h3>
<p>Score: {site.overall_score.toFixed(1)}/10</p>
<p>{site.reasoning}</p>
</div>
))}
</div>
);
}
export default LunarSiteExplorer;
šÆ Best Practices
1. Search Strategy Workflow
Step 1: Start Broad
⢠Large radius (100km)
⢠Relaxed filters
⢠Goal: Overview of available sites
Step 2: Refine
⢠Decrease radius (50km)
⢠Tighten filters (max_hazard, min_visibility)
⢠Goal: Focus on most promising areas
Step 3: Get Recommendations
⢠Use /recommendations endpoint
⢠Specify mission_type
⢠Goal: Mission-specific intelligent ranking
Step 4: Compare Finalists
⢠Use /compare on top 3-5 candidates
⢠Goal: Understand trade-offs
Step 5: Verify
⢠Get full details with /batch
⢠Goal: Final validation
2. Filter Guidelines
Conservative (High-stakes crewed missions)
params = {
"max_hazard": 1.5,
"min_visibility": 70.0,
"max_slope": 10.0
}
# Use case: Artemis landing sites
Moderate (Standard robotic missions)
params = {
"max_hazard": 2.0,
"min_visibility": 50.0,
"max_slope": 15.0
}
# Use case: Commercial landers, science missions
Exploratory (Scouting/contingency sites)
params = {
"max_hazard": 2.5,
"min_visibility": 30.0,
"max_slope": 20.0
}
# Use case: Rover traverses, backup sites
3. Performance Optimization
| Operation |
Typical Latency |
Notes |
/search (10 results) |
40-60ms |
Most common query |
/batch (10 sites) |
15-25ms |
Optimized bulk retrieval |
/recommendations |
80-120ms |
Complex multi-site scoring |
/compare |
30-50ms |
Side-by-side analysis |
For Fast Queries (<50ms):
- Apply stricter filters to reduce result processing
- Use batch endpoint for multiple site lookups
- Cache results when querying repeatedly
š” Data Sources & Methodology
Terrain Data
- Source: NASA LOLA (Lunar Orbiter Laser Altimeter)
- Resolution: 5 meters per pixel
- Coverage: -90° to -83.5° latitude (lunar south pole)
- Derived Metrics: Slope, roughness, relief, hazard index
Illumination Data
- Source: NASA LROC (Lunar Reconnaissance Orbiter Camera)
- Resolution: 60-240m (latitude-dependent)
- Coverage: Full lunar south pole
- Metrics: Visibility percentage over lunar year
Processing Pipeline
- Download NASA PDS data archives (polar projection)
- Generate 1.18M candidate landing sites from source rasters
- Extract terrain and illumination metrics at each site
- Store in PostGIS database as WGS84 coordinates (EPSG:4326)
- Calculate composite hazard index
- Create spatial indexes (GiST) for fast queries
Feature Analysis Scales
All terrain and illumination features are computed at three analysis radii:
- 25m radius: Fine-scale local terrain (immediate landing zone)
- 50m radius: Medium-scale neighborhood (landing approach area)
- 100m radius: Coarse-scale regional context (area operations)
The API returns 100m radius data by default as it provides the most reliable and comprehensive metrics.
Hazard Index Scale
The hazard index is a composite metric (0-3) combining slope, roughness, and relief:
- 0.0-1.0: Excellent - Safe for all mission types
- 1.0-2.0: Good - Acceptable for most missions
- 2.0-2.5: Moderate - Requires careful evaluation
- 2.5-3.0: High - Challenging terrain, not recommended
Data Quality
- Total Sites: 1,180,127
- Complete Data: 99.98% (1,179,905 sites)
- Coordinate System: WGS84 lat/lon (EPSG:4326)
- Distance Method: Spherical calculations via PostGIS Geography
- Spatial Accuracy: Meter-based distances accurate at high latitudes
š¬ Support
Documentation & Resources
Contact & Help
- Email: info@irisdatalabs.com
- Bug Reports: Email with subject "API Bug Report"
- Feature Requests: We'd love to hear your ideas!
Beta Program
ā
Free access during beta (100 requests/day)
ā
Your feedback helps shape the product
ā
Direct influence on future features
ā ļø Breaking changes possible (with email notification)
Citation
If you use this API in research, please cite:
Iris Data Labs (2025). Lunar Landing Site API: Intelligent site selection
powered by NASA terrain and illumination data.
https://lunarlandingsiteapi.up.railway.app
š Changelog
v1.0.0 (October 30, 2025) - Current
š Initial Public Beta Release
Authentication
- API key authentication via
X-API-Key header
- Beta tier: 100 requests/day
- Usage tracking in all authenticated responses
Data
- 1,180,127 analyzed landing sites
- 60+ features per site
- 99.98% data completeness
Endpoints
- 6 total endpoints (2 status + 2 data + 2 decision support)
- Mission-specific intelligent recommendations
- Side-by-side site comparison
- Bulk site retrieval
Features
- Sub-100ms query performance
- Plain English reasoning
- Mission-specific scoring (Artemis, robotic, rover, custom)
- Automatic warning and strength detection
Known Limitations
- Coverage limited to lunar south pole (-90° to -83.5° lat)
- Maximum 100 sites per search query
Coming Soon
- Premium tier (Coming Soon)
- Additional export formats (GeoJSON/KML/CSV)
- Expanded coverage areas