Skip to main content

Phytopedia API Overview

The Phytopedia API provides RESTful endpoints to access educational content about cannabis, hemp, herbs, and wellness.

Base URL

Production: https://admin.phytopedia.co/api
Local Dev: http://localhost:3001/api

Authentication

All API requests require authentication via JWT token or API key.

Getting Your API Key

  1. Log in to admin.phytopedia.co
  2. Navigate to SettingsAPI Keys
  3. Click Generate New Key
  4. Copy and store securely

Using API Key

Include in request headers:

Authorization: Bearer YOUR_API_KEY

Quick Start

Fetch All Articles

curl -X GET "https://admin.phytopedia.co/api/articles" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"success": true,
"articles": [
{
"id": "uuid",
"title": "Benefits of CBD Oil",
"slug": "benefits-of-cbd-oil",
"excerpt": "Learn about the therapeutic benefits...",
"content": "Full article content...",
"featured_image": "https://...",
"category_id": "uuid",
"published_at": "2025-11-01T00:00:00Z"
}
],
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_articles": 42,
"limit": 10
}
}

Get Daily Fact

curl -X GET "https://admin.phytopedia.co/api/facts/random"

Response:

{
"success": true,
"fact": {
"id": "uuid",
"fact_text": "Hemp can grow up to 15 feet tall in just 3-4 months!",
"category_id": "uuid",
"is_active": true
}
}

List Categories

curl -X GET "https://admin.phytopedia.co/api/categories"

Response:

{
"success": true,
"categories": [
{
"id": "uuid",
"name": "The World of Cannabis",
"slug": "cannabis",
"description": "Educational content about cannabis...",
"type": "basic",
"price": 0.00
},
{
"id": "uuid",
"name": "Unleash Your Mind",
"slug": "nootropics",
"description": "Cognitive enhancers and brain health...",
"type": "premium",
"price": 9.99
}
]
}

Available Endpoints

Articles

MethodEndpointDescription
GET/articlesList all articles (paginated)
GET/articles/:idGet single article by ID
GET/articles?category=:slugFilter by category
GET/articles?search=:querySearch articles
POST/articlesCreate article (admin only)
PUT/articles/:idUpdate article (admin only)
DELETE/articles/:idDelete article (admin only)

Categories

MethodEndpointDescription
GET/categoriesList all categories
GET/categories/:idGet single category
POST/categoriesCreate category (admin only)
PUT/categories/:idUpdate category (admin only)

Daily Facts

MethodEndpointDescription
GET/factsList all facts
GET/facts/todayGet today's fact
GET/facts/randomGet random fact
POST/factsCreate fact (admin only)

Authentication

MethodEndpointDescription
POST/auth/registerRegister new user
POST/auth/loginLogin (returns JWT)
GET/auth/profileGet current user
POST/auth/forgot-passwordRequest password reset

Query Parameters

Pagination

GET /api/articles?page=1&limit=10
ParameterTypeDefaultDescription
pagenumber1Page number
limitnumber10Items per page (max 100)

Filtering

GET /api/articles?category=cannabis&status=published
ParameterTypeDescription
categorystringCategory slug
statusstringdraft, published, archived
featuredbooleantrue or false
GET /api/articles?search=cbd+benefits
ParameterTypeDescription
searchstringSearch in title and content

Rate Limits

API requests are rate-limited based on your subscription tier:

TierRequests per HourBurst Limit
FREE10020
PRO1,000200
PREMIUM10,0002,000

Rate Limit Headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1635724800

Error Handling

HTTP Status Codes

CodeMeaningDescription
200OKRequest successful
201CreatedResource created
400Bad RequestInvalid parameters
401UnauthorizedMissing or invalid auth token
403ForbiddenInsufficient permissions
404Not FoundResource not found
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error

Error Response Format

{
"success": false,
"message": "Article not found",
"error_code": "ARTICLE_NOT_FOUND"
}

Code Examples

JavaScript (Fetch API)

const apiKey = 'YOUR_API_KEY';
const baseUrl = 'https://admin.phytopedia.co/api';

async function getArticles() {
const response = await fetch(`${baseUrl}/articles?limit=10`, {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
});

const data = await response.json();
return data.articles;
}

// Usage
getArticles().then(articles => {
console.log('Articles:', articles);
});

PHP (cURL)

<?php
$apiKey = 'YOUR_API_KEY';
$url = 'https://admin.phytopedia.co/api/articles';

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
]);

$response = curl_exec($ch);
$data = json_decode($response, true);

echo 'Articles: ' . count($data['articles']);
curl_close($ch);
?>

Python (Requests)

import requests

api_key = 'YOUR_API_KEY'
base_url = 'https://admin.phytopedia.co/api'

headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}

response = requests.get(f'{base_url}/articles', headers=headers)
data = response.json()

print(f"Articles: {len(data['articles'])}")

Best Practices

1. Cache Responses

Cache API responses to reduce requests:

// Cache for 5 minutes
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedArticles() {
const cacheKey = 'articles';
const cached = cache.get(cacheKey);

if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}

const articles = await getArticles();
cache.set(cacheKey, { data: articles, timestamp: Date.now() });

return articles;
}

2. Handle Errors Gracefully

async function getArticles() {
try {
const response = await fetch(`${baseUrl}/articles`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});

if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error('Failed to fetch articles:', error);
return { success: false, articles: [] };
}
}

3. Respect Rate Limits

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);

if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await delay(retryAfter * 1000);
continue;
}

return response;
}

throw new Error('Max retries exceeded');
}

Next Steps

Need Help?


API Version: 2.0.0 Last Updated: November 2025