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

  1. Create an account — an organization is created for you.
  2. Open Dashboard → API keys and create a key. Copy it: it is shown only once.
  3. Store it as an environment variable, e.g. NAIJAPRESS_API_KEY, on your server.
  4. Make a request:
curl
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

text
https://api.naijapress.com

News endpoints

EndpointDescription
GET /v1/newsNewest-first list with filters, optional q keyword filter, cursor pagination.
GET /v1/news/{slug}One article by slug or id.
GET /v1/news/{slug}/relatedArticles 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):

json
{
  "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 }
}

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.

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

ParameterExamplePlan
categoryeconomyAll
sourcesource id or slugAll
published_after / published_before2026-10-01T00:00:00ZAll
language, q, sorten, naira, published_ascAll
subcategory, topic, entity, locationbanking, fuel-subsidy, central-bank-of-nigeria, lagosStartup and above
geographic_scope, location_rolenational, eventGrowth and above

Error codes

Errors use one envelope: { "error": { "code", "message", "details" } }.

StatusCodeMeaning
422query_too_shortThe free-text search query is shorter than 3 characters; `details.min_length` gives the minimum.
422query_too_longThe free-text search query is longer than your plan's maximum; `details.max_length` gives the maximum.
400bad_request / invalid_filter / invalid_cursorA parameter value is not recognised (e.g. unknown category) or the cursor is malformed.
401missing_api_key / invalid_api_keyNo key was sent, or it is wrong, revoked or expired.
403plan_restrictedThe endpoint, field filter or capability is not part of your plan.
403organization_suspendedAPI access for your organization is suspended.
404not_foundThe resource does not exist, or (for articles) is outside your plan's access window.
422validation_errorA parameter failed validation; `details` lists each problem.
429rate_limitedPer-minute limit exceeded. Wait `Retry-After` seconds.
429quota_exceededMonthly quota used. Resets at the start of the next UTC month.
503embedding_unavailableSemantic 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 /v1 request 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 returns 429 rate_limited. Both include Retry-After.
  • Send an Idempotency-Key header 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.

PlanPriceRequests / 30 daysArticles / callRate limitNews accessSearch query lengthMax. articles / 30 days*
Developer Free₦05035/minDelayed 12 hours (news 12–24 hours old)3–5 characters150
Startup₦20,000/month1,000510/minLast 30 days3–10 characters5,000
Growth₦50,000/month5,0001020/minLast 6 months3–20 characters50,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.