LunarFeed API Documentation

Gateway to Global Information Streams

🔹
LunarCryptoScrollBoost v1.1

Overview

The LunarCrypto API provides access to translated cryptocurrency news articles from trusted global sources. Each client receives an API key with configurable limits on request frequency, items per request, and total daily usage.

Real-time Translation

High-quality translation for crypto news in multiple languages

Smart Scrolling

ScrollBoost v1.1 with bidirectional pagination support

Professional Grade

Enterprise-ready with SLA support and custom solutions

Authentication

All API requests require authentication using an API key passed in the X-API-Key header. Each client is assigned a unique API key with specific rate limits and access permissions.

🔑 Getting Your API Key

If you don't have an API key, please contact your LunarFeed representative or reach out to [email protected] for client agreement and key provisioning.

HTTP Headers
X-API-Key: your_client_api_key
Accept: application/json

Get Translated Articles

Fetch a list of translated cryptocurrency articles in the specified language. The latest ScrollBoost v1.1 update introduces smart scrolling with direction support, enabling efficient pagination of both newer and older content.

🚀 ScrollBoost v1.1 Features

  • • Bidirectional scrolling with direction parameter
  • • Smart pagination for efficient content loading
  • • Improved performance for large datasets
  • • Backward compatibility with v1.0

Request Parameters

ParameterTypeRequiredDescription
langstringOptionalTarget language code (fa, it, en, arb). Default: fa
limitintegerOptionalNumber of items to return (1-100). Default: 10
directionstringOptionalScroll direction: "newer" (latest) or "older" (previous)

Example Requests

cURL
curl -X GET "https://api.lunarfeed.online/api/v1/crypto/articles/translated/?lang=en&limit=5&direction=newer" \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/json"
JavaScript
const response = await fetch(
  'https://api.lunarfeed.online/api/v1/crypto/articles/translated/?lang=en&limit=10&direction=newer',
  {
    headers: {
      'X-API-Key': 'your_api_key_here',
      'Accept': 'application/json'
    }
  }
);

const articles = await response.json();

Pagination & Scrolling

ScrollBoost v1.1 introduces intelligent pagination with bidirectional scrolling capabilities. The system uses checkpoint-based navigation for efficient content loading.

🔄 How Scrolling Works

  • • Each response includes checkpoint data for next/previous pages
  • • Use direction=newer for latest content
  • • Use direction=older for historical content (limited to the past 2 days)
  • • Checkpoint tokens are automatically managed by the API

Newer Fetch Example

python

import requests

API_KEY = "your_api_key_here"
BASE_URL = "https://api.lunarfeed.online/api/v1/crypto/articles/translated/"

def fetch_newer(limit=10):
    response = requests.get(BASE_URL, headers={
        "X-API-Key": API_KEY,
        "Accept": "application/json"
    }, params={
        "limit": limit,
        "direction": "newer"
    })

    response.raise_for_status()
    articles = response.json()

    if not articles:
        print("No new articles available.")
    else:
        print(f"Fetched {len(articles)} newer articles.")

    return articles

Older Fetch Example

python
def fetch_older(limit=10):
    response = requests.get(BASE_URL, headers={
        "X-API-Key": API_KEY,
        "Accept": "application/json"
    }, params={
        "limit": limit,
        "direction": "older"
    })

    response.raise_for_status()
    articles = response.json()

    if not articles:
        print("No more historical articles.")
    else:
        print(f"Fetched {len(articles)} older articles.")

    return articles

Snapshot API

Access real-time snapshots of translated crypto articles - clean, structured, and ready for instant use. Unlike the scroll-based feed, this endpoint is optimized for real-time system polling and ingestion. *Snapshot endpoint is stateless and always returns the latest available articles at the time of request.

⚡ Perfect for Real-time Systems

  • • Low-latency content ingestion
  • • Caching and alerting engines
  • • Dashboard and pre-render pipelines
  • • Systems that sync every few minutes without managing scroll state

Endpoint

GET https://api.lunarfeed.online/api/v1/crypto/articles/translated/latest-snapshot/

This endpoint returns the latest available batch of translated crypto news, ideal for systems that need to sync once every few minutes without managing scroll state.

Query Parameters

ParameterTypeRequiredDescription
langstringOptionalTarget translation language (en, fa, it, arb)
limitintegerOptionalMax number of items to return. Default: 20

If no language is provided, the default translation is used.

Example Requests

cURL
curl -X GET "https://api.lunarfeed.online/api/v1/crypto/articles/translated/latest-snapshot/?lang=en&limit=10" \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/json"
JavaScript
// Real-time polling example
const pollSnapshots = async () => {
  try {
    const response = await fetch(
      'https://api.lunarfeed.online/api/v1/crypto/articles/translated/latest-snapshot/?lang=en&limit=20',
      {
        headers: {
          'X-API-Key': 'your_api_key_here',
          'Accept': 'application/json'
        }
      }
    );
    
    const articles = await response.json();
    console.log(`Received ${articles.length} articles`);
    
    // Process articles for your system
    processArticles(articles);
    
  } catch (error) {
    console.error('Snapshot polling failed:', error);
  }
};

// Poll every 5 minutes
setInterval(pollSnapshots, 5 * 60 * 1000);
Python
import requests
import time

def fetch_snapshot(lang='en', limit=20):
    headers = {
        "X-API-Key": "your_api_key_here",
        "Accept": "application/json"
    }
    
    params = {
        "lang": lang,
        "limit": limit
    }
    
    response = requests.get(
        "https://api.lunarfeed.online/api/v1/crypto/articles/translated/latest-snapshot/",
        headers=headers,
        params=params
    )
    
    return response.json()

# Real-time ingestion loop
while True:
    try:
        articles = fetch_snapshot()
        print(f"Ingested {len(articles)} articles")
        
        # Process articles for your system
        process_articles(articles)
        
        # Wait 5 minutes before next poll
        time.sleep(300)
        
    except Exception as e:
        print(f"Error: {e}")
        time.sleep(60)  # Wait 1 minute on error

Sample Response

JSON
[
  {
    "id": "654abc123def456",
    "title_translated": "Bitcoin Hits New High Amid Institutional Interest",
    "summary_translated": "Bitcoin crosses $70,000 as major institutions announce new crypto investment strategies...",
    "language": "en",
    "original_source": "https://cryptonews.example.com/bitcoin-institutional-interest",
    "created_at": "2025-07-08T10:34:00Z"
  },
  {
    "id": "789ghi456jkl123",
    "title_translated": "Ethereum Network Upgrade Shows Promising Results",
    "summary_translated": "The latest Ethereum upgrade demonstrates improved transaction speeds and reduced gas fees...",
    "language": "en", 
    "original_source": "https://blockchain.example.com/ethereum-upgrade-results",
    "created_at": "2025-07-08T10:28:15Z"
  }
]

🎯 Use Cases

  • Real-time Dashboards: Live crypto news feeds
  • Alert Systems: Trigger notifications on breaking news
  • Content Caching: Pre-populate content management systems
  • Data Ingestion: Feed analytics and ML pipelines
  • Mobile Apps: Background sync for offline reading
  • Trading Bots: News-based trading signal generation

Response Structure

The API returns a JSON array of article objects. Each article contains standardized fields for easy integration and rendering in your application.

JSON
[
  {
    "original_id": 1800,
    "language": "en",
    "translated_title": "Bitcoin Reaches New All-Time High Amid Institutional Adoption",
    "translated_content": "### Market Analysis\n\nBitcoin has surged to unprecedented levels...",
    "created_at": "2025-06-27T07:06:37.558344",
    "meta": {
      "token_mentioned": "BTC",
      "has_watermark": false,
      "thumbnail_url": "https://cdn.lunarfeed.com/thumbnails/1800.jpg"
    }
  }
]

Response Fields Reference

Complete reference for all fields returned in article objects. Understanding these fields will help you integrate and display content effectively in your application.

FieldTypeDescriptionExample
original_idintegerUnique identifier for the original article1800
languagestringTarget translation language codeen
translated_titlestringArticle title in requested languageBitcoin Reaches New High
translated_contentstringFull article content with markdown formatting### Analysis\\n\\nBitcoin has...
created_atstringISO 8601 timestamp of article creation2025-06-27T07:06:37.558344
metaobjectAdditional metadata about the article{ token_mentioned: 'BTC' }
meta.token_mentionedstringPrimary cryptocurrency token discussedBTC, ETH, ADA
meta.has_watermarkbooleanWhether article contains watermarkfalse
meta.thumbnail_urlstringURL to article thumbnail imagehttps://cdn.lunarfeed.com/...

💡 Field Usage Tips

  • • Use original_id for deduplication and caching
  • token_mentioned helps with content categorization
  • created_at is in UTC timezone
  • thumbnail_url may be null for some articles

Error Handling

The API uses standard HTTP status codes and returns structured error responses. Proper error handling ensures robust integration with your application.

Common Error Codes

  • 400 - Bad Request (invalid parameters)
  • 401 - Unauthorized (invalid API key)
  • 429 - Rate limit exceeded
  • 500 - Internal server error

Error Response Format

JSON
{
    "detail": "Invalid API key"
}

Error Handling Examples

JavaScript
import requests

def fetch_articles(api_key: str, lang: str = 'en', limit: int = 10):
    """
    Fetch translated cryptocurrency articles from LunarFeed API.

    Args:
        api_key (str): Your LunarFeed API key.
        lang (str): Target language for translation (default: 'en').
        limit (int): Number of articles to fetch (default: 10).

    Returns:
        list: List of translated article objects.

    Raises:
        Exception: If the request fails or the API returns an error.
    """
    url = "https://api.lunarfeed.online/api/v1/crypto/articles/translated/"
    headers = {
        "X-API-Key": api_key,
        "Accept": "application/json"
    }
    params = {
        "lang": lang,
        "limit": limit
    }

    try:
        response = requests.get(url, headers=headers, params=params)

        # Check for HTTP errors
        if response.status_code != 200:
            try:
                error_data = response.json()
                detail = error_data.get("detail", "Unknown error")
                raise Exception(f"Error {response.status_code}: {detail}")
            except ValueError:
                raise Exception(f"Error {response.status_code}: Unable to parse error response")

        # Return parsed JSON data
        return response.json()

    except requests.exceptions.RequestException as e:
        raise Exception(f"Request failed: {str(e)}")

SDK & Code Libraries

Ready-to-use code examples and libraries for popular programming languages. These examples include error handling, rate limiting, and best practices.

Python SDK

Full-featured Python library

Node.js Package

NPM package with TypeScript

Postman Collection

Ready-to-import API collection

Python Implementation

Python
import requests
import time
from typing import Optional, List, Dict

class LunarFeedClient:
    def __init__(self, api_key: str, base_url: str = "https://api.lunarfeed.online"):
        self.api_key = api_key
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": api_key,
            "Accept": "application/json"
        })
    
    def get_articles(self, lang: str = "en", limit: int = 10, 
                    direction: str = "newer") -> List[Dict]:
        """Fetch translated crypto articles"""
        params = {
            "lang": lang,
            "limit": limit,
            "direction": direction
        }
        
        response = self.session.get(
            f"{self.base_url}/api/v1/crypto/articles/translated/",
            params=params
        )
        
        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 60))
            raise Exception(f"Rate limited. Retry after {retry_after} seconds")
        
        response.raise_for_status()
        return response.json()
    
    def get_snapshot(self, lang: str = "en", limit: int = 20) -> List[Dict]:
        """Get latest snapshot of articles"""
        params = {"lang": lang, "limit": limit}
        
        response = self.session.get(
            f"{self.base_url}/api/v1/crypto/articles/translated/latest-snapshot/",
            params=params
        )
        
        response.raise_for_status()
        return response.json()

# Usage example
client = LunarFeedClient("your_api_key_here")

try:
    articles = client.get_articles(lang="en", limit=5)
    print(f"Fetched {len(articles)} articles")
    
    for article in articles:
        print(f"- {article['translated_title']}")
        
except Exception as e:
    print(f"Error: {e}")

PHP Implementation

PHP
<?php

class LunarFeedClient {
    private $apiKey;
    private $baseUrl;
    
    public function __construct($apiKey, $baseUrl = 'https://api.lunarfeed.online') {
        $this->apiKey = $apiKey;
        $this->baseUrl = $baseUrl;
    }
    
    public function getArticles($lang = 'en', $limit = 10, $direction = 'newer') {
        $params = http_build_query([
            'lang' => $lang,
            'limit' => $limit,
            'direction' => $direction
        ]);
        
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'header' => [
                    "X-API-Key: {$this->apiKey}",
                    "Accept: application/json"
                ]
            ]
        ]);
        
        $url = "{$this->baseUrl}/api/v1/crypto/articles/translated/?{$params}";
        $response = file_get_contents($url, false, $context);
        
        if ($response === false) {
            throw new Exception('Failed to fetch articles');
        }
        
        return json_decode($response, true);
    }
    
    public function getSnapshot($lang = 'en', $limit = 20) {
        $params = http_build_query(['lang' => $lang, 'limit' => $limit]);
        
        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'header' => [
                    "X-API-Key: {$this->apiKey}",
                    "Accept: application/json"
                ]
            ]
        ]);
        
        $url = "{$this->baseUrl}/api/v1/crypto/articles/translated/latest-snapshot/?{$params}";
        $response = file_get_contents($url, false, $context);
        
        return json_decode($response, true);
    }
}

// Usage
$client = new LunarFeedClient('your_api_key_here');

try {
    $articles = $client->getArticles('en', 5);
    echo "Fetched " . count($articles) . " articles\n";
    
    foreach ($articles as $article) {
        echo "- " . $article['translated_title'] . "\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

?>

Go Implementation

Go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "time"
)

type LunarFeedClient struct {
    APIKey  string
    BaseURL string
    Client  *http.Client
}

type Article struct {
    OriginalID        int    `json:"original_id"`
    Language          string `json:"language"`
    TranslatedTitle   string `json:"translated_title"`
    TranslatedContent string `json:"translated_content"`
    CreatedAt         string `json:"created_at"`
    Meta              struct {
        TokenMentioned string `json:"token_mentioned"`
        HasWatermark   bool   `json:"has_watermark"`
        ThumbnailURL   string `json:"thumbnail_url"`
    } `json:"meta"`
}

func NewLunarFeedClient(apiKey string) *LunarFeedClient {
    return &LunarFeedClient{
        APIKey:  apiKey,
        BaseURL: "https://api.lunarfeed.online",
        Client:  &http.Client{Timeout: 30 * time.Second},
    }
}

func (c *LunarFeedClient) GetArticles(lang string, limit int, direction string) ([]Article, error) {
    params := url.Values{}
    params.Add("lang", lang)
    params.Add("limit", fmt.Sprintf("%d", limit))
    params.Add("direction", direction)
    
    reqURL := fmt.Sprintf("%s/api/v1/crypto/articles/translated/?%s", c.BaseURL, params.Encode())
    
    req, err := http.NewRequest("GET", reqURL, nil)
    if err != nil {
        return nil, err
    }
    
    req.Header.Set("X-API-Key", c.APIKey)
    req.Header.Set("Accept", "application/json")
    
    resp, err := c.Client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
    }
    
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    
    var articles []Article
    err = json.Unmarshal(body, &articles)
    return articles, err
}

func main() {
    client := NewLunarFeedClient("your_api_key_here")
    
    articles, err := client.GetArticles("en", 5, "newer")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Fetched %d articles\n", len(articles))
    for _, article := range articles {
        fmt.Printf("- %s\n", article.TranslatedTitle)
    }
}

Performance & Best Practices

Optimize your integration with these performance tips and best practices. Proper implementation ensures efficient resource usage and better user experience.

⚡ Performance Tips

  • • Cache responses using original_id
  • • Use appropriate limit values (10-50 recommended)
  • • Implement exponential backoff for retries
  • • Use snapshot API for real-time polling
  • • Compress requests with gzip when possible

🛡️ Security Best Practices

  • • Store API keys securely (environment variables)
  • • Never expose API keys in client-side code
  • • Use HTTPS for all API requests
  • • Implement proper error handling
  • • Monitor API usage and set alerts

Caching Strategy Example

JavaScript
class LunarFeedCache {
  constructor(ttl = 300000) { // 5 minutes default TTL
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  set(key, value) {
    this.cache.set(key, {
      value,
      timestamp: Date.now()
    });
  }
  
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    if (Date.now() - item.timestamp > this.ttl) {
      this.cache.delete(key);
      return null;
    }
    
    return item.value;
  }
  
  clear() {
    this.cache.clear();
  }
}

class OptimizedLunarFeedClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.cache = new LunarFeedCache();
    this.requestQueue = [];
    this.processing = false;
  }
  
  async getArticles(params = {}) {
    const cacheKey = JSON.stringify(params);
    const cached = this.cache.get(cacheKey);
    
    if (cached) {
      console.log('Returning cached result');
      return cached;
    }
    
    const articles = await this.fetchArticles(params);
    this.cache.set(cacheKey, articles);
    
    return articles;
  }
  
  async fetchArticles(params) {
    const queryString = new URLSearchParams(params).toString();
    const response = await fetch(
      `https://api.lunarfeed.online/api/v1/crypto/articles/translated/?${queryString}`,
      {
        headers: {
          'X-API-Key': this.apiKey,
          'Accept': 'application/json',
          'Accept-Encoding': 'gzip'
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return await response.json();
  }
}
python
import requests
import time
import json
from typing import Optional

class LunarFeedCache:
    def __init__(self, ttl: int = 300):  # Default TTL: 5 minutes (in seconds)
        self.cache = {}
        self.ttl = ttl

    def set(self, key: str, value: dict):
        self.cache[key] = {
            'value': value,
            'timestamp': time.time()
        }

    def get(self, key: str) -> Optional[dict]:
        item = self.cache.get(key)
        if not item:
            return None
        
        if time.time() - item['timestamp'] > self.ttl:
            del self.cache[key]
            return None

        return item['value']

    def clear(self):
        self.cache.clear()


class OptimizedLunarFeedClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.cache = LunarFeedCache()
        self.base_url = "https://api.lunarfeed.online"

    def get_articles(self, lang: str = "en", limit: int = 10, direction: str = "newer"):
        params = {
            "lang": lang,
            "limit": limit,
            "direction": direction
        }

        cache_key = json.dumps(params, sort_keys=True)
        cached = self.cache.get(cache_key)
        if cached:
            print("🔁 Returning cached result")
            return cached

        url = f"{self.base_url}/api/v1/crypto/articles/translated/"
        headers = {
            "X-API-Key": self.api_key,
            "Accept": "application/json",
            "Accept-Encoding": "gzip"
        }

        response = requests.get(url, headers=headers, params=params)

        if response.status_code != 200:
            raise Exception(f"HTTP {response.status_code}: {response.text}")

        data = response.json()
        self.cache.set(cache_key, data)
        return data


# Usage Example
client = OptimizedLunarFeedClient("your_api_key_here")
try:
    articles = client.get_articles(lang="en", limit=5)
    print(f"✅ Fetched {len(articles)} articles")
except Exception as e:
    print(f"❌ Error: {e}")

Rate Limiting & Retry Logic

JavaScript
class RateLimitedClient {
  constructor(apiKey, requestsPerMinute = 60) {
    this.apiKey = apiKey;
    this.requestsPerMinute = requestsPerMinute;
    this.requestTimes = [];
  }
  
  async makeRequest(url, options = {}) {
    await this.waitForRateLimit();
    
    const response = await fetch(url, {
      ...options,
      headers: {
        'X-API-Key': this.apiKey,
        'Accept': 'application/json',
        ...options.headers
      }
    });
    
    this.requestTimes.push(Date.now());
    
    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
      console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
      await this.sleep(retryAfter * 1000);
      return this.makeRequest(url, options); // Retry
    }
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  async waitForRateLimit() {
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
    
    // Remove old requests
    this.requestTimes = this.requestTimes.filter(time => time > oneMinuteAgo);
    
    if (this.requestTimes.length >= this.requestsPerMinute) {
      const oldestRequest = this.requestTimes[0];
      const waitTime = 60000 - (now - oldestRequest);
      
      if (waitTime > 0) {
        console.log(`Rate limit reached. Waiting ${waitTime}ms...`);
        await this.sleep(waitTime);
      }
    }
  }
  
  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}
python
import time
import requests
from collections import deque
from typing import Optional

class RateLimitedClient:
    def __init__(self, api_key: str, requests_per_minute: int = 60):
        self.api_key = api_key
        self.requests_per_minute = requests_per_minute
        self.request_times = deque()

    def _wait_for_rate_limit(self):
        now = time.time()
        one_minute_ago = now - 60

        # Remove outdated timestamps
        while self.request_times and self.request_times[0] < one_minute_ago:
            self.request_times.popleft()

        if len(self.request_times) >= self.requests_per_minute:
            oldest = self.request_times[0]
            wait_time = 60 - (now - oldest)
            if wait_time > 0:
                print(f"⏳ Rate limit reached. Waiting {int(wait_time)} seconds...")
                time.sleep(wait_time)

    def make_request(self, url: str, params: Optional[dict] = None) -> dict:
        self._wait_for_rate_limit()

        headers = {
            "X-API-Key": self.api_key,
            "Accept": "application/json"
        }

        try:
            response = requests.get(url, headers=headers, params=params)
            self.request_times.append(time.time())

            if response.status_code == 429:
                retry_after = int(response.headers.get("Retry-After", 60))
                print(f"🚫 Rate limited. Retrying in {retry_after} seconds...")
                time.sleep(retry_after)
                return self.make_request(url, params)  # Retry

            response.raise_for_status()
            return response.json()

        except requests.RequestException as e:
            print(f"❌ Request failed: {e}")
            raise

# Usage Example
if __name__ == "__main__":
    client = RateLimitedClient("your_api_key_here", requests_per_minute=60)
    
    try:
        result = client.make_request(
            "https://api.lunarfeed.online/api/v1/crypto/articles/translated/",
            params={"lang": "en", "limit": 5}
        )
        print(f"✅ Fetched {len(result)} articles")
    except Exception as e:
        print(f"❌ Error: {e}")

Support & Contact

Technical Support

Business Inquiries

  • API extensions & custom solutions
  • Enterprise partnerships
  • White-label solutions

© 2025 LunarFeed. All rights reserved. | Empowering localized news intelligence across global markets.