Documentation
Introduction
NaijaPress gives you access to Nigerian news through a single API for research, analytics, business intelligence, and software development. We ingest news from approved Nigerian and relevant international publishers and add exactly one primary category from a fixed 12-category taxonomy, a controlled subcategory, canonical entities, curated topics and geographic metadata. Everything is available through a versioned REST API under /v1 that returns JSON. Responses link to the publisher's original article. Growth and Enterprise responses also include an AI-generated summary of the publisher's reporting. Full article text is not returned by default.
Enrichment happens asynchronously after ingestion, so newly published articles appear in the API once they have been processed. Timestamps are UTC, in ISO 8601.
Quick start
- Create an account — an organization is created for you.
- Open Dashboard → API keys and create a key. Copy it: it is shown only once.
- Store it as an environment variable, e.g.
NAIJAPRESS_API_KEY, on your server. - Make a request:
curl "https://api.naijapress.com/v1/news?category=economy&limit=5" \
-H "Authorization: Bearer $NAIJAPRESS_API_KEY"Authentication & API keys
Send your key as a bearer token: Authorization: Bearer np_live_… (the X-API-Key header is also accepted). Keys belong to your organization; owners and admins can create, rotate and revoke them. Revoked keys stop working immediately.
NaijaPress stores only a keyed hash of each key, so we cannot show it again — rotate it if you lose it. Never put API keys in browser or mobile code: requests from a browser are visible in its network tools. Call NaijaPress from your server and pass results to your front end.
Base URL
https://api.naijapress.comNews endpoints
| Endpoint | Description |
|---|---|
GET /v1/news | Newest-first list with filters, optional q keyword filter, cursor pagination. |
GET /v1/news/{slug} | One article by slug or id. |
GET /v1/news/{slug}/related | Articles in the same event cluster or sharing canonical entities/topics within ±14 days (Growth and Enterprise). |
An article response looks like this (example values; fields not included in your plan are omitted):
{
"data": [
{
"id": "art_7Qd2kLm9Vx3aPz1B",
"slug": "cbn-retains-monetary-policy-rate-k3x9qa",
"title": "CBN retains monetary policy rate",
"source": {
"id": "src_Y8sJ2nQp0LwE4tRz",
"name": "Example Publisher",
"url": "https://publisher.example/cbn-retains-rate",
"website": "https://publisher.example"
},
"published_at": "2026-10-28T10:00:00Z",
"ingested_at": "2026-10-28T10:04:12Z",
"language": "en",
"summary": "Example Publisher reports that the Central Bank of Nigeria kept its benchmark rate unchanged at its latest meeting.",
"category": { "slug": "finance_markets", "name": "Finance & Markets" },
"subcategory": { "slug": "banking", "name": "Banking" },
"entities": [
{ "id": "ent_…", "name": "Central Bank of Nigeria", "slug": "central-bank-of-nigeria", "type": "financial_institution", "salience": 0.9 }
],
"topics": [{ "id": "top_…", "label": "Interest Rates", "slug": "interest-rates" }],
"geography": {
"mentioned_locations": [{ "id": "plc_…", "name": "Abuja", "slug": "abuja-city", "type": "city" }],
"event_location": null,
"geographic_scope": "national"
},
"attribution": "Source: Example Publisher (https://publisher.example/cbn-retains-rate). Summary and metadata by NaijaPress."
}
],
"pagination": { "limit": 10, "next_cursor": "eyJwIjoi…", "has_more": true }
}Keyword search
GET /v1/search?q=… uses PostgreSQL full-text search over the article title (highest weight) and indexed article metadata, ranked by ts_rank_cd with recency as tie-breaker. Query syntax supports "exact phrases", or, and -exclusion. It works whether or not an article has an embedding.
Every free-text query (q on /v1/search, /v1/search/semantic, /v1/search/hybrid and /v1/news) must be at least 3 characters and at most your plan's maximum search query length (see Plans). The query is trimmed and repeated spaces collapsed before counting characters. Shorter queries return 422 query_too_short, longer ones 422 query_too_long, and neither uses a request credit; empty queries return 422 validation_error. Structured parameters such as category, source, entity or article ids are never length-checked.
Semantic & hybrid search
GET /v1/search/semantic?q=… embeds your query and returns the nearest articles by cosine similarity. Article embeddings are computed from each article's title and processed metadata. score is cosine similarity in [−1, 1] (higher is closer). It is a ranking signal, not a probability. Use min_similarity to drop weak matches.
GET /v1/search/hybrid?q=… retrieves up to 100 candidates from each of the keyword and semantic rankings and combines them with Reciprocal Rank Fusion: score = Σ 1 / (60 + rank) over the lists an article appears in. This avoids adding incomparable raw scores. Each result includes match.keyword_rank, match.semantic_rank and match.semantic_similarity. Articles without embeddings still appear through the keyword list; if the embedding service is unavailable, meta.semantic_available is false and results are keyword-only.
Categories & subcategories
Every classified article has exactly one primary category: politics, economy, business, finance_markets, technology, health, education, entertainment, sports, crime_security, transport, lifestyle. International stories are classified by subject. Subcategories come from a controlled registry; articles that fit none are null (unclassified). Endpoints: GET /v1/categories, /v1/categories/{slug}, /v1/categories/{slug}/subcategories, /v1/subcategories/{slug}.
Entities
Canonical people, companies, agencies, parties and institutions. Aliases such as “CBN” resolve to one record. GET /v1/entities?q=cbn&type=financial_institution, GET /v1/entities/{id or slug}, GET /v1/entities/{id}/news. Only reviewed (approved) entities are listed.
Topics
Recurring subjects and issues, curated by our team. New topics suggested by the AI are reviewed before they are published. GET /v1/topics, /v1/topics/{id}, /v1/topics/{id}/news.
Locations
Countries, Nigeria's geopolitical zones, states and cities, with parent relationships. Each article distinguishes mentioned_locations from event_location (only set when the text makes it clear) and gives a geographic_scope. Filtering by a state includes its cities. GET /v1/locations?type=state, /v1/locations/{id}, /v1/locations/{id}/news?role=event.
Sources
GET /v1/sources and /v1/sources/{id} return public publisher metadata only.
Pagination
List responses have the shape { data: [...], pagination: { limit, next_cursor, has_more } }. Pass next_cursor as cursor to get the next page. Cursors are opaque. Each call returns at most your plan's articles per call (see Plans); a larger limit is capped to that maximum, and each page is a separate request credit. Search results can be paged up to 1,000 results deep.
Filtering
| Parameter | Example | Plan |
|---|---|---|
category | economy | All |
source | source id or slug | All |
published_after / published_before | 2026-10-01T00:00:00Z | All |
language, q, sort | en, naira, published_asc | All |
subcategory, topic, entity, location | banking, fuel-subsidy, central-bank-of-nigeria, lagos | Startup and above |
geographic_scope, location_role | national, event | Growth and above |
Error codes
Errors use one envelope: { "error": { "code", "message", "details" } }.
| Status | Code | Meaning |
|---|---|---|
| 422 | query_too_short | The free-text search query is shorter than 3 characters; `details.min_length` gives the minimum. |
| 422 | query_too_long | The free-text search query is longer than your plan's maximum; `details.max_length` gives the maximum. |
| 400 | bad_request / invalid_filter / invalid_cursor | A parameter value is not recognised (e.g. unknown category) or the cursor is malformed. |
| 401 | missing_api_key / invalid_api_key | No key was sent, or it is wrong, revoked or expired. |
| 403 | plan_restricted | The endpoint, field filter or capability is not part of your plan. |
| 403 | organization_suspended | API access for your organization is suspended. |
| 404 | not_found | The resource does not exist, or (for articles) is outside your plan's access window. |
| 422 | validation_error | A parameter failed validation; `details` lists each problem. |
| 429 | rate_limited | Per-minute limit exceeded. Wait `Retry-After` seconds. |
| 429 | quota_exceeded | Monthly quota used. Resets at the start of the next UTC month. |
| 503 | embedding_unavailable | Semantic search is temporarily unavailable (hybrid search degrades to keyword). |
Rate limits & quotas
Each organization has a per-minute rate limit and a monthly request quota, both enforced on the server and shared by all of the organization's API keys. They are independent: a request can be within the monthly quota and still exceed the per-minute limit. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Limit and X-Quota-Remaining. On 429, wait for Retry-After seconds.
- Each authenticated
/v1request uses one credit, however many articles it returns. Monthly quotas count API calls, not articles. - Not counted: server errors (5xx), rate/quota rejections (429), authentication or plan rejections (401/403), and invalid requests (400/422, e.g. a search query below your plan's minimum). Not-found responses are counted.
- Exceeding the monthly quota returns
429 quota_exceeded; exceeding the per-minute limit returns429 rate_limited. Both includeRetry-After. - Send an
Idempotency-Keyheader when retrying: repeated requests with the same key within 10 minutes count once. - Quotas reset every 30 days, counted from the start of your subscription (on the free plan, from when you signed up). Your dashboard shows the current cycle's start and reset dates. Upgrading or changing plan starts a new 30-day cycle.
Plans & access restrictions
Every limit below is enforced by the API on every endpoint: news listings, article lookups, search, related news, and entity, topic and location listings. Articles outside your plan's access window return 404 and never appear in results, even if you omit date parameters or request an older range.
Developer has no live and no historical news: it sees articles published between 12 and 24 hours ago, a window that moves continuously. Paid plans get live news as it arrives, plus history counted in whole calendar days in Nigeria time (WAT), today = day 1, moving forward at midnight. Example, if today is 30 October: Startup sees articles published 1–30 October; Growth sees the last 180 days and Enterprise the last 365 days.
| Plan | Price | Requests / 30 days | Articles / call | Rate limit | News access | Search query length | Max. articles / 30 days* |
|---|---|---|---|---|---|---|---|
| Developer Free | ₦0 | 50 | 3 | 5/min | Delayed 12 hours (news 12–24 hours old) | 3–5 characters | 150 |
| Startup | ₦20,000/month | 1,000 | 5 | 10/min | Last 30 days | 3–10 characters | 5,000 |
| Growth | ₦50,000/month | 5,000 | 10 | 20/min | Last 6 months | 3–20 characters | 50,000 |
* Theoretical maximum: requests per 30 days × articles per call, assuming every request returns the full allowed number of articles. It is not a guaranteed article count.
The Developer Free plan returns primary categories only. Startup adds subcategories, entities, topics, geography and sentiment. Growth adds AI summaries, related news, semantic and hybrid search, event clusters and advanced filters. Enterprise includes everything in Growth; the figures above are its standard defaults, and quotas, pricing, history, rate limits, query length, support and integrations are negotiated per customer. See pricing.
Content attribution
Article content belongs to its publishers. When you display NaijaPress data, show the publisher's name and link to source.url. Each article includes an attribution string you can display. Summaries, classification and metadata describe the publisher's reporting and do not mean NaijaPress verified its claims. Full article text is never returned by default; it is available only for sources whose licensing permits redistribution, on plans that include it.
Public vs admin endpoints
This documentation and the API reference cover the public /v1 API, which uses API keys. The website's own endpoints (/auth, /account) and operator endpoints (/admin) use browser sessions, are not part of the public API, and cannot be accessed with API keys.