API reference
The API Ghana API
Every endpoint you can call with an API key, and the public ones: what each takes, what it answers and how it fails. New here? The quickstart gets you to a first answer in a minute.
https://connect.apighana.comOn this page
Getting started
- Create a free account. Your API key is shown once, on your account page.
- Send it as the
X-API-Keyheader.districts,regionsandpublic_holidaysare free on every key, so this works straight away:
curl "https://connect.apighana.com/api/data/districts?limit=5" \ -H "X-API-Key: $APIGHANA_KEY"
Or import the Postman collection, paste your key into the environment and send any request. Everything outside News, Exports and Webhooks works on a free key.
Authentication
Send your key as the X-API-Key header on every request. Keys are 64 characters. The key is not accepted in the query string, and Authorization: Bearer is read as a website sign-in, not a key (the MCP server is the one exception).
Call the API from your server. Browsers are blocked by CORS in production, and a key in a web page or mobile app can be copied by anyone who opens it. Keys are stored hashed: we cannot show yours again, only replace it (account page → Regenerate), which stops the old one at once.
Endpoints marked No key needed are public. Those marked Key optional answer without a key; with one, your plan decides how much history or which features you get.
Responses and paging
Every answer is JSON in the same envelope: status (success or error), a message written to be read, data, and on lists a meta with the paging.
Page with page (from 1) and limit; meta.total and meta.total_pages say how far to go. Market history pages with a cursor instead: after=meta.next_cursor.
Rows come with meta.source: the source, its licence, when we last updated the data and what period it covers. Show it wherever you show the figures.
Every answer has an X-Request-Id header. Send your own X-Request-Id (8 to 128 letters, digits, -, _, . or :) and it is echoed back; quote it when you write to us about a call. Public answers are cached for a few minutes and say so in Cache-Control and X-Cache.
Limits
| Plan | Requests a minute | Rows per page | Market history | News API | Exports | Webhooks |
|---|---|---|---|---|---|---|
| Free | 60 | 50 | 7 days | — | — | — |
| Developer | 600 | 500 | 90 days | Yes | — | — |
| Business | 3,000 | 5,000 | All | Yes | CSV, Parquet | Yes |
| Enterprise | 10,000 | 10,000 | All | Yes | CSV, Parquet | Yes |
The per-minute limit applies to the data, query and ask endpoints, and counts per account, so a new key does not reset it. Every account also has a ceiling of 1,000 requests per 15 minutes across all endpoints, whatever the plan. Spread bulk work out, use exports for whole datasets, or ask us about higher limits.
RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset describe the 15-minute ceiling. On data, query and ask endpoints a RateLimit header describes your plan's minute, e.g. limit=600, remaining=598, reset=42. A 429 carries Retry-After in seconds.
Plain-English questions have a daily allowance of their own: Free 10, Developer 50, Business 200, Enterprise 500. See pricing for everything else each plan includes.
Errors
Errors use the same envelope with status: "error", a message you can show, and where it helps a code, an errors list naming bad fields, or data saying what to do next.
{
"status": "error",
"message": "'health_facilities' is not on your key. Licence it for a year, use a free pick if you have one left, or move to the Developer plan for the whole catalogue.",
"code": "ACCESS_REQUIRED",
"data": {
"options": {
"dataset": "health_facilities",
"dataset_id": 1,
"included": false,
"reason": "access_required",
"free_pick_remaining": 3,
"yearly_single_ghs": 49,
"yearly_single_usd": 3.72,
"yearly_single_available": true,
"packs": [],
"plans_path": "/pricing"
}
}
}| Status | Meaning |
|---|---|
| 200 | Success. 201 when something was created. |
| 400 | The request is malformed: an unknown column, a bad filter or body. message says what, errors lists fields. |
| 401 | No key, or the key is wrong or revoked. Send it as X-API-Key. |
| 403 | The key cannot do this: the dataset is not on it (ACCESS_REQUIRED), the plan does not include it (PLAN_REQUIRED), or the key is inactive. |
| 404 | No dataset, row, series or route by that name. |
| 409 | The dataset cannot be queried (no column definitions). |
| 429 | Too many requests. Wait for Retry-After seconds. |
| 500 | Our side. Retry with backoff; quote the request_id in the answer to us. |
| 503 | A part of the service is unavailable for a moment. Retry with backoff. |
| Code | Status | Meaning |
|---|---|---|
| ACCESS_REQUIRED | 403 | The dataset is not on your key. data.options lists the ways to get it. |
| PLAN_REQUIRED | 403 | The endpoint needs a higher plan (News API: Developer; exports and webhooks: Business). |
| ASK_LIMIT | 429 | Today's plain-English questions are used up. |
| TOO_MANY | 429 | Too many running exports (3) or webhook endpoints (10). |
| BAD_URL | 400 | A webhook URL that is not a public https address. |
| BAD_EVENTS | 400 | No known webhook event chosen. |
| ASK_NOT_CONFIGURED | 503 | Asking is switched off on our side. |
Catalogue
What datasets exist, what their columns are and where each comes from. All public: no key needed. The dataset name is what every other endpoint takes.
Every dataset with its description, sector, price, source, licence and freshness.
Query parameters
- pageintegerdefault 1
Page number, from 1.
- limitintegerdefault 10
Datasets per page, up to 100.
- searchstring
Matches the name or description.
- categoryinteger
A category id from GET /api/categories.
priceis the yearly licence in cedis;0means free on every key.
curl "https://connect.apighana.com/api/datasets?page=1&limit=2"
{
"status": "success",
"message": "Datasets fetched successfully.",
"data": [
{
"id": 1,
"name": "health_facilities",
"description": "Hospitals, clinics, health centres and doctors across Ghana, with region, district and coordinates. Derived from OpenStreetMap. 1186 records.",
"endpoint": "/api/data/health_facilities",
"version": "1.0",
"price": 49,
"price_usd": null,
"requiresAuth": true,
"category": 1,
"category_name": "Health",
"data_as_of": "2026-09-18",
"last_checked_at": "2026-09-25T02:07:11.341+00:00",
"check_status": "warning",
"update_frequency": "monthly",
"source_name": "OpenStreetMap contributors",
"source_url": "https://www.openstreetmap.org/copyright",
"licence": "ODbL",
"coverage_start": null,
"coverage_end": null,
"coverage_column": null,
"enrichment": null,
"created_at": "2026-09-16T14:48:47.221879+00:00",
"updated_at": "2026-09-18T22:46:18.987+00:00"
}
],
"meta": {
"total": 284,
"page": 1,
"limit": 2,
"total_pages": 142
}
}One dataset's documentation: its columns and types, source, licence and freshness. Takes a name or an id.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Errors
- 404 No dataset by that name.
curl "https://connect.apighana.com/api/datasets/districts"
{
"status": "success",
"message": "Dataset fetched successfully",
"data": {
"id": 77,
"name": "districts",
"description": "Ghana's metropolitan, municipal and district assemblies with their region, land area and centroid. 260 records.",
"endpoint": "/api/data/districts",
"version": "1.0",
"price": 0,
"price_usd": null,
"requiresAuth": true,
"created_at": "2026-09-16T14:55:46.241304+00:00",
"updated_at": "2026-09-18T22:46:50.243+00:00",
"data_as_of": "2026-09-18",
"coverage_start": null,
"coverage_end": null,
"coverage_column": null,
"last_checked_at": "2026-09-25T02:04:23.445+00:00",
"check_status": "ok",
"update_frequency": "monthly",
"source_name": "geoBoundaries ADM2",
"source_url": "https://www.geoboundaries.org/",
"licence": "CC BY 4.0",
"category": 21,
"category_name": "Geography",
"schema": {
"columns": [
{
"name": "id",
"type": "BIGSERIAL PRIMARY KEY"
},
{
"name": "name",
"type": "TEXT NOT NULL"
},
{
"name": "region",
"type": "TEXT"
},
{
"name": "boundary_id",
"type": "TEXT"
},
{
"name": "area_sqkm",
"type": "DECIMAL(12,2)"
},
{
"name": "centroid_latitude",
"type": "DECIMAL(9,6)"
},
{
"name": "centroid_longitude",
"type": "DECIMAL(9,6)"
},
{
"name": "source",
"type": "TEXT"
}
]
},
"api_parameters": null,
"api_headers": null,
"api_status_codes": null,
"api_examples": null,
"total_calls": 0,
"usage_per_month": 0
}
}The dataset's recorded versions, newest first, with rows added, removed and changed. Up to 100.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
- A version with
exportable: truecan be passed asversionto the export endpoint.
curl "https://connect.apighana.com/api/datasets/districts/versions"
{
"status": "success",
"message": "Versions retrieved",
"data": [
{
"id": 21,
"dataset_name": "districts",
"version": "2026-09-18",
"version_date": "2026-09-18",
"row_count": 260,
"rows_added": 260,
"rows_removed": 0,
"rows_changed": 0,
"note": "First check",
"created_at": "2026-09-18T02:49:25.695525+00:00",
"exportable": true
}
]
}The sectors datasets are grouped into, with how many datasets each has.
curl "https://connect.apighana.com/api/categories"
{
"status": "success",
"message": "Categories retrieved successfully",
"data": [
{
"id": 20,
"name": "Agriculture",
"description": "Agriculture datasets for Ghana.",
"created_at": "2026-09-16T14:48:42.96785+00:00",
"updated_at": "2026-09-16T14:48:42.96785+00:00",
"dataset_count": 26
}
]
}The first five rows of any dataset, paid ones included, and its column names. Use it to see a dataset before you licence it.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Errors
- 404 No dataset by that name.
curl "https://connect.apighana.com/api/data/districts/preview"
{
"status": "success",
"message": "Preview of 'districts': the first 5 records.",
"data": [
{
"id": 1,
"name": "Adenta Municipal",
"region": "Greater Accra Region",
"boundary_id": "2480657B26321648161032",
"area_sqkm": 78.47,
"centroid_latitude": 5.703203,
"centroid_longitude": -0.119929,
"source": "geoBoundaries ADM2 (CC BY 4.0)",
"reference_date": null
},
{
"id": 2,
"name": "Ledzokuku Municipal",
"region": "Greater Accra Region",
"boundary_id": "2480657B94892111901595",
"area_sqkm": 29.44,
"centroid_latitude": 5.594821,
"centroid_longitude": -0.124979,
"source": "geoBoundaries ADM2 (CC BY 4.0)",
"reference_date": null
}
],
"meta": {
"preview": true,
"preview_rows": 5,
"total": 260,
"columns": [
"id",
"name",
"region",
"boundary_id",
"area_sqkm",
"centroid_latitude",
"centroid_longitude",
"source",
"reference_date"
]
}
}Data rows
A dataset's rows, paged. Free datasets work on every key; any other dataset needs a licence, a free pick, a pack, or the Developer plan or higher.
A page of rows, in id order, with the total and where the data comes from.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Query parameters
- pageintegerdefault 1
Page number, from 1.
- limitintegerdefault 10
Rows per page. Capped at your plan's rows per page (Free 50, Developer 500, Business 5,000, Enterprise 10,000).
- filterstring
Exact matches,
column:valuepairs joined by commas. Case-sensitive; values cannot contain commas. - searchstring
Case-insensitive match across the text columns, up to 200 characters.
- When
limitis above your plan's cap, the page is cut to the cap andmessagesays so. meta.sourcenames the source, its licence and when the data was last updated. Show it wherever you show the figures.
Errors
- 400 A bad
filterorsearch, or a filter on a column the dataset does not have. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 404 No dataset by that name.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl "https://connect.apighana.com/api/data/districts?page=1&limit=2" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Records fetched from 'districts'.",
"data": [
{
"id": 1,
"name": "Adenta Municipal",
"region": "Greater Accra Region",
"boundary_id": "2480657B26321648161032",
"area_sqkm": 78.47,
"centroid_latitude": 5.703203,
"centroid_longitude": -0.119929,
"source": "geoBoundaries ADM2 (CC BY 4.0)",
"reference_date": null
},
{
"id": 2,
"name": "Ledzokuku Municipal",
"region": "Greater Accra Region",
"boundary_id": "2480657B94892111901595",
"area_sqkm": 29.44,
"centroid_latitude": 5.594821,
"centroid_longitude": -0.124979,
"source": "geoBoundaries ADM2 (CC BY 4.0)",
"reference_date": null
}
],
"meta": {
"page": 1,
"limit": 2,
"total": 260,
"total_items": 260,
"total_pages": 130,
"is_limited": true,
"source": {
"dataset": "districts",
"source": "geoBoundaries ADM2",
"source_url": "https://www.geoboundaries.org/",
"licence": "CC BY 4.0",
"last_updated": "2026-09-18",
"last_checked": "2026-09-25T02:04:23.445+00:00",
"covers": null,
"notice": "Source: geoBoundaries ADM2 (CC BY 4.0). Last updated from the source on 2026-09-18. The records are a snapshot of the source as of the date it was last updated. Provided as published by the source, without warranty. Check the dates before relying on a figure."
}
}
}One row by its id.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools. - idinteger
The row's
id.
Errors
- 400
idis not a positive integer. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 404 No dataset, or no row with that id.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl "https://connect.apighana.com/api/data/districts/1" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Record fetched from 'districts'.",
"data": {
"id": 1,
"name": "Adenta Municipal",
"region": "Greater Accra Region",
"boundary_id": "2480657B26321648161032",
"area_sqkm": 78.47,
"centroid_latitude": 5.703203,
"centroid_longitude": -0.119929,
"source": "geoBoundaries ADM2 (CC BY 4.0)",
"reference_date": null
}
}The dataset's column names and types. The same columns are listed publicly by GET /api/datasets/{table}.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 404 No dataset by that name.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl "https://connect.apighana.com/api/datasets/extended/schema/districts" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Dataset schema retrieved successfully.",
"data": {
"columns": [
{
"name": "id",
"type": "BIGSERIAL PRIMARY KEY"
},
{
"name": "name",
"type": "TEXT NOT NULL"
},
{
"name": "region",
"type": "TEXT"
},
{
"name": "boundary_id",
"type": "TEXT"
},
{
"name": "area_sqkm",
"type": "DECIMAL(12,2)"
},
{
"name": "centroid_latitude",
"type": "DECIMAL(9,6)"
},
{
"name": "centroid_longitude",
"type": "DECIMAL(9,6)"
},
{
"name": "source",
"type": "TEXT"
}
]
}
}How many rows the dataset has, and when it was created and last changed.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 404 No dataset by that name.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl "https://connect.apighana.com/api/datasets/extended/stats/districts" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Statistics for dataset 'districts'.",
"data": {
"total_records": 260,
"created_at": "2026-09-16T14:55:46.241304+00:00",
"updated_at": "2026-09-18T22:46:50.243+00:00"
}
}Query builder
Choose columns, filter with operators and sort, in one JSON body. Column names come from the dataset's schema; an unknown column is an error, not an empty answer.
Rows matching every where condition, with the columns you choose, in the order you choose.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Body (JSON)
- selectstring[]default ["*"]
Columns to return.
- whereobject[]default []
Conditions, all of which must hold:
{ column, operator, value }. Operators:=,!=,>,<,>=,<=,IN(value is a non-empty array),CONTAINS(case-insensitive text match). - orderobject
{ column, direction }, directionascordesc. - limitintegerdefault 10
1 to 1,000. Capped at your plan's rows per page (Free 50, Developer 500, Business 5,000, Enterprise 10,000).
- pageintegerdefault 1
Page number, from 1.
- A
limitabove your plan's cap is lowered to the cap without an error.
Errors
- 400 A bad body, or a column in
select,whereororderthat the dataset does not have.errorsnames the field. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 404 No dataset by that name.
- 409 The dataset has no column definitions to query against.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl -X POST "https://connect.apighana.com/api/query/districts" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"select": [
"name",
"region",
"area_sqkm"
],
"where": [
{
"column": "name",
"operator": "IN",
"value": [
"Wa East",
"Wa Municipal"
]
}
],
"order": {
"column": "area_sqkm",
"direction": "desc"
},
"limit": 10
}'{
"status": "success",
"message": "Custom query executed successfully.",
"data": [
{
"name": "Wa East",
"region": "Upper West Region",
"area_sqkm": 4325
},
{
"name": "Wa Municipal",
"region": "Upper West Region",
"area_sqkm": 583.44
}
],
"meta": {
"total": 2,
"total_items": 2,
"total_pages": 1,
"page": 1,
"limit": 10,
"source": {
"dataset": "districts",
"source": "geoBoundaries ADM2",
"source_url": "https://www.geoboundaries.org/",
"licence": "CC BY 4.0",
"last_updated": "2026-09-18",
"last_checked": "2026-09-25T02:04:23.445+00:00",
"covers": null,
"notice": "Source: geoBoundaries ADM2 (CC BY 4.0). Last updated from the source on 2026-09-18. The records are a snapshot of the source as of the date it was last updated. Provided as published by the source, without warranty. Check the dates before relying on a figure."
}
}
}Ask in plain English
Ask a question in words and get an answer worked out from the rows, with the queries that produced it. Each question counts against a daily allowance: Free 10, Developer 50, Business 200, Enterprise 500 (reset at midnight, Accra time). Bought questions are used after that.
Answers a question from one dataset's rows.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Body (JSON)
- questionstringrequired
1 to 2,000 characters.
- historyobject[]default []
Earlier turns for follow-up questions, up to 8:
{ role: "user" | "assistant", content }.
Errors
- 400 No
question, or one over 2,000 characters. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 429
ASK_LIMITToday's questions are used up and there are no bought ones left. - 503
ASK_NOT_CONFIGUREDAsking is switched off on our side.
curl -X POST "https://connect.apighana.com/api/datasets/districts/ask" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "How many districts are there?"
}'{
"status": "success",
"message": "Chat with data answered.",
"data": {
"answer": "The districts dataset lists 260 districts.",
"tools": [
{
"name": "run_query",
"args": {
"table": "districts"
},
"summary": "Queried districts: 1 rows (260 match)"
}
],
"dataset": {
"id": 77,
"name": "districts"
},
"sources": [
{
"dataset": "districts",
"source": "geoBoundaries ADM2",
"source_url": "https://www.geoboundaries.org/",
"licence": "CC BY 4.0",
"last_updated": "2026-09-18",
"last_checked": "2026-09-25T02:04:23.445+00:00",
"covers": null,
"notice": "Source: geoBoundaries ADM2 (CC BY 4.0). Last updated from the source on 2026-09-18. The records are a snapshot of the source as of the date it was last updated. Provided as published by the source, without warranty. Check the dates before relying on a figure."
}
],
"mode": "dataset",
"quota": {
"used": 1,
"limit": 10,
"remaining": 9,
"day": "2026-09-25",
"credits": 0
}
}
}Answers a question from any dataset your key can read; it chooses the datasets itself.
Body (JSON)
- questionstringrequired
1 to 2,000 characters.
- historyobject[]default []
Earlier turns, up to 8.
Errors
- 400 No
question, or one over 2,000 characters. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 429
ASK_LIMITToday's questions are used up and there are no bought ones left. - 503
ASK_NOT_CONFIGUREDAsking is switched off on our side.
curl -X POST "https://connect.apighana.com/api/datasets/ask" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "How many regions does Ghana have?"
}'{
"status": "success",
"message": "Chat with data answered.",
"data": {
"answer": "Ghana has 16 regions, according to the regions dataset.",
"tools": [
{
"name": "list_datasets",
"args": {
"query": "regions"
},
"summary": "Listed 3 datasets"
},
{
"name": "run_query",
"args": {
"table": "regions"
},
"summary": "Queried regions: 16 rows (16 match)"
}
],
"dataset": null,
"sources": [],
"mode": "catalogue",
"quota": {
"used": 2,
"limit": 10,
"remaining": 8,
"day": "2026-09-25",
"credits": 0
}
}
}Live and markets
Exchange rates, bank rates, fuel, food and commodity prices and economic indicators, updated through the day. No key needed for the latest values; a key's plan sets how much history comes back. The two families name their groups differently: /api/live uses fx banks fuel food commodities macro, /api/market uses rates banks fuel food commodities indicators.
Every live series with its latest and previous value, grouped. Add points for recent history to draw a line.
Query parameters
- groupstring
fx,banks,fuel,food,commoditiesormacro. - pointsintegerdefault 0
Recent observations per series, 0 to 120.
curl "https://connect.apighana.com/api/live"
{
"status": "success",
"message": "Live data",
"data": {
"groups": {
"fx": [
{
"id": 12,
"slug": "fx-usd-ghs",
"name": "US dollar to cedi",
"group": "fx",
"unit": "GHS per USD",
"frequency": "daily",
"source_name": "exchangerate-api.com",
"source_url": "https://www.exchangerate-api.com",
"licence": "Free for use with attribution",
"description": "How many Ghana cedis one US dollar buys, mid-market, updated daily.",
"dataset_name": "fx_rates",
"dimensions": {
"base": "USD",
"quote": "GHS"
},
"latest_value": 11.5673,
"latest_at": "2026-09-25T00:00:01+00:00",
"previous_value": 11.574,
"previous_at": "2026-09-24T00:00:02+00:00",
"change_pct": -0.0579,
"first_at": "2026-09-18T00:00:01+00:00",
"observation_count": 9,
"stale": false,
"points": []
}
]
},
"series": [
{
"id": 12,
"slug": "fx-usd-ghs",
"name": "US dollar to cedi",
"group": "fx",
"unit": "GHS per USD",
"frequency": "daily",
"source_name": "exchangerate-api.com",
"source_url": "https://www.exchangerate-api.com",
"licence": "Free for use with attribution",
"description": "How many Ghana cedis one US dollar buys, mid-market, updated daily.",
"dataset_name": "fx_rates",
"dimensions": {
"base": "USD",
"quote": "GHS"
},
"latest_value": 11.5673,
"latest_at": "2026-09-25T00:00:01+00:00",
"previous_value": 11.574,
"previous_at": "2026-09-24T00:00:02+00:00",
"change_pct": -0.0579,
"first_at": "2026-09-18T00:00:01+00:00",
"observation_count": 9,
"stale": false,
"points": []
}
],
"updated_at": null
}
}One series and its observations, oldest first.
Path parameters
- slugstring
A series slug from GET /api/live, e.g.
fx-usd-ghs,fuel-petrol,commodity-gold.
Query parameters
- rangestringdefault 1y
30d,90d,1y,5yorall. - limitintegerdefault 2000
Most points returned, 1 to 5,000.
- Without a key, and on Free and Developer, a daily series goes back 92 days, a monthly one 2 years and an annual one all the way. Business, Enterprise and owners of the series' dataset get all of it.
- Only Business and Enterprise get figures from within the day; other plans get the last figure of each day.
Errors
- 401 A key was sent but is wrong or revoked. Leave the header out to call without one.
- 404 No series with that slug.
curl "https://connect.apighana.com/api/live/fx-usd-ghs?range=30d"
{
"status": "success",
"message": "Series retrieved",
"data": {
"id": 12,
"slug": "fx-usd-ghs",
"name": "US dollar to cedi",
"group": "fx",
"unit": "GHS per USD",
"frequency": "daily",
"source_name": "exchangerate-api.com",
"source_url": "https://www.exchangerate-api.com",
"licence": "Free for use with attribution",
"description": "How many Ghana cedis one US dollar buys, mid-market, updated daily.",
"dataset_name": "fx_rates",
"dimensions": {
"base": "USD",
"quote": "GHS"
},
"latest_value": 11.5673,
"latest_at": "2026-09-25T00:00:01+00:00",
"previous_value": 11.574,
"previous_at": "2026-09-24T00:00:02+00:00",
"change_pct": -0.0579,
"first_at": "2026-09-18T00:00:01+00:00",
"observation_count": 9,
"stale": false,
"points": [
{
"t": "2026-09-23T00:00:01+00:00",
"v": 11.5805
},
{
"t": "2026-09-24T00:00:02+00:00",
"v": 11.574
},
{
"t": "2026-09-25T00:00:01+00:00",
"v": 11.5673
}
]
},
"meta": {
"range": "30d",
"truncated": false,
"free_window_days": 92,
"history_days": 92,
"plan": null,
"intraday": false,
"dataset": {
"name": "fx_rates",
"price": 9,
"endpoint": "/api/data/fx_rates"
}
}
}The latest value of every series in one group.
Path parameters
- groupstring
rates,banks,fuel,commodities,foodorindicators.
- On
banks, Free keys and callers without a key see five banks;meta.bank_by_banksays when the list is cut.
Errors
- 401 A key was sent but is wrong or revoked.
- 404 Unknown market group.
curl "https://connect.apighana.com/api/market/rates"
{
"status": "success",
"message": "Latest rates",
"data": [
{
"id": 13,
"slug": "fx-gbp-ghs",
"name": "British pound to cedi",
"group": "fx",
"unit": "GHS per GBP",
"frequency": "daily",
"source_name": "exchangerate-api.com",
"source_url": "https://www.exchangerate-api.com",
"licence": "Free for use with attribution",
"dimensions": {
"base": "GBP",
"quote": "GHS"
},
"latest_value": 15.29257007,
"latest_at": "2026-09-25T00:00:01+00:00",
"previous_value": 15.33996024,
"previous_at": "2026-09-24T00:00:02+00:00",
"change_pct": -0.3089,
"first_at": "2026-09-18T00:00:01+00:00",
"observation_count": 9,
"stale": false
}
],
"meta": {
"group": "fx",
"plan": "free",
"history_days": 7,
"as_of": "2026-09-25T00:00:01+00:00"
}
}Observations for a group, or one series in it, between two dates. Paged with a cursor.
Path parameters
- groupstring
rates,banks,fuel,commodities,foodorindicators.
Query parameters
- seriesstring
One series slug. Leave out for the whole group.
- currencystring
Only series whose base currency is this, e.g.
USD. - fromstring
Start date,
YYYY-MM-DD. Clipped to your plan's history. - tostring
End date,
YYYY-MM-DD. - limitintegerdefault 500
Observations per page, 1 to 5,000.
- orderstringdefault asc
ascordesc. - afterstring
meta.next_cursorfrom the previous page.
- History here follows the plan: 7 days without a key and on Free, 90 on Developer, everything on Business and Enterprise.
meta.clippedis true whenfromwas moved forward. - Keep asking with
after = meta.next_cursoruntil it is null.
Errors
- 400 A bad date, cursor or limit.
- 401 A key was sent but is wrong or revoked.
- 404 Unknown market group.
curl "https://connect.apighana.com/api/market/rates/history?series=fx-usd-ghs&limit=3"
{
"status": "success",
"message": "rates history",
"data": [
{
"series": "fx-usd-ghs",
"observed_at": "2026-09-19T00:00:01+00:00",
"value": 11.426
},
{
"series": "fx-usd-ghs",
"observed_at": "2026-09-20T00:00:01+00:00",
"value": 11.4837
},
{
"series": "fx-usd-ghs",
"observed_at": "2026-09-21T00:00:01+00:00",
"value": 11.5608
}
],
"meta": {
"series": [
{
"slug": "fx-usd-ghs",
"name": "US dollar to cedi",
"unit": "GHS per USD",
"frequency": "daily",
"dimensions": {
"base": "USD",
"quote": "GHS"
}
}
],
"plan": "free",
"history_days": 7,
"from": "2026-09-18T08:50:41.415Z",
"to": null,
"clipped": true,
"upgrade": "Your plan reads 7 days of history. Developer reads 90 days, Business everything.",
"next_cursor": "MjAyNi0wOS0yMVQwMDowMDowMSswMDowMHwxMg",
"count": 3,
"intraday": false
}
}Every series' value as recorded in today's snapshot, taken once a day. data is null before the first snapshot.
curl "https://connect.apighana.com/api/market/snapshot"
{
"status": "success",
"message": "Daily snapshot",
"data": {
"snapshot_date": "2026-09-25",
"rows": [
{
"slug": "fx-usd-ghs",
"group": "fx",
"value": 11.5673,
"observed_at": "2026-09-25T00:00:01+00:00",
"is_carried_forward": false,
"source": "exchangerate-api.com",
"raw": {
"unit": "GHS per USD",
"frequency": "daily",
"change_pct": -0.0579,
"previous_at": "2026-09-24T00:00:02+00:00",
"previous_value": 11.574
}
}
]
}
}News
Ghanaian news, sorted into sections, with outlet and link. With an API key this is the News API, which comes with the Developer plan and up: a Free key gets 403 PLAN_REQUIRED. The same endpoints answer without a key, as they do for the website.
Stories, newest first.
Query parameters
- pageintegerdefault 1
Page number, from 1.
- limitintegerdefault 30
Stories per page, up to 100.
- categorystring
politics,business,technology,health,education,energy,agriculture,environment,sports,entertainment,society,worldorgeneral. - qstring
Words in the headline or summary, up to 100 characters.
- sourcestring
A source slug from GET /api/news/sources.
- tagstring
A tag.
- outletstring
The outlet's domain.
- fromstring
Published on or after,
YYYY-MM-DD. - tostring
Published on or before,
YYYY-MM-DD. - sentimentstring
positive,neutralornegative. - entitystring
A person, company or place named in the story.
Errors
- 401 A key was sent but is wrong or revoked.
- 403
PLAN_REQUIREDNeeds the Developer plan or higher.
curl "https://connect.apighana.com/api/news?page=1&limit=1" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "News retrieved",
"data": [
{
"id": 3879,
"slug": "gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor-31239d",
"url": "https://asaaseradio.com/gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor",
"headline": "Gold shipments resume, boosting Ghana's forex reserves, says BoG governor",
"summary": "Fresh gold shipments from Ghana are accelerating foreign exchange reserve accumulation, with the Bank of Ghana confirming a significant export spike, though volatile international gold prices remain a challenge.",
"image_url": null,
"source_name": "Asaase Radio",
"source_domain": "asaaseradio.com",
"author": "Winifred Lartey",
"category": "business",
"tags": [
"gold",
"bank of ghana",
"forex reserves",
"exports"
],
"region": "national",
"published_at": "2026-09-25T08:03:47+00:00",
"clicks": 0,
"sentiment": null,
"entities": []
}
],
"meta": {
"total": 923,
"page": 1,
"limit": 1,
"total_pages": 923
}
}Each section with how many stories it has.
Errors
- 403
PLAN_REQUIREDNeeds the Developer plan or higher.
curl "https://connect.apighana.com/api/news/categories" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Categories retrieved",
"data": [
{
"category": "politics",
"count": 296
},
{
"category": "business",
"count": 251
}
]
}The outlets and feeds stories come from.
Errors
- 403
PLAN_REQUIREDNeeds the Developer plan or higher.
curl "https://connect.apighana.com/api/news/sources" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Sources retrieved",
"data": [
{
"id": 1,
"name": "MyJoyOnline",
"slug": "myjoyonline",
"homepage": "https://www.myjoyonline.com",
"kind": "rss",
"item_count": 1172
}
]
}The most-read recent stories.
Query parameters
- limitintegerdefault 8
Up to 20.
Errors
- 403
PLAN_REQUIREDNeeds the Developer plan or higher.
curl "https://connect.apighana.com/api/news/trending?limit=1" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Trending retrieved",
"data": [
{
"id": 3879,
"slug": "gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor-31239d",
"url": "https://asaaseradio.com/gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor",
"headline": "Gold shipments resume, boosting Ghana's forex reserves, says BoG governor",
"summary": "Fresh gold shipments from Ghana are accelerating foreign exchange reserve accumulation, with the Bank of Ghana confirming a significant export spike, though volatile international gold prices remain a challenge.",
"image_url": null,
"source_name": "Asaase Radio",
"source_domain": "asaaseradio.com",
"author": "Winifred Lartey",
"category": "business",
"tags": [
"gold",
"bank of ghana",
"forex reserves",
"exports"
],
"region": "national",
"published_at": "2026-09-25T08:03:47+00:00",
"clicks": 0,
"sentiment": null,
"entities": []
}
]
}One story and related ones.
Path parameters
- slugstring
The story's
slug.
Errors
- 403
PLAN_REQUIREDNeeds the Developer plan or higher. - 404 No story with that slug.
curl "https://connect.apighana.com/api/news/story/gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor-31239d" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Story retrieved",
"data": {
"id": 3879,
"slug": "gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor-31239d",
"url": "https://asaaseradio.com/gold-shipments-resume-boosting-ghanas-forex-reserves-bog-governor",
"headline": "Gold shipments resume, boosting Ghana's forex reserves, says BoG governor",
"summary": "Fresh gold shipments from Ghana are accelerating foreign exchange reserve accumulation, with the Bank of Ghana confirming a significant export spike, though volatile international gold prices remain a challenge.",
"image_url": null,
"source_name": "Asaase Radio",
"source_domain": "asaaseradio.com",
"author": "Winifred Lartey",
"category": "business",
"tags": [
"gold",
"bank of ghana",
"forex reserves",
"exports"
],
"region": "national",
"published_at": "2026-09-25T08:03:47+00:00",
"clicks": 0,
"sentiment": null,
"entities": [],
"related": []
}
}Exports
Whole datasets and long market histories as files. Exports come with the Business plan and up; other plans get 403 PLAN_REQUIRED.
The dataset as a CSV or Excel file, streamed. Up to 250,000 rows.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Query parameters
- formatstringdefault csv
csvorxlsx. - versionstring
A version from GET /api/datasets/{table}/versions,
YYYY-MM-DD. Leave out for the current rows.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
PLAN_REQUIREDNeeds the Business plan or higher. - 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 404 No dataset, or no such version.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl "https://connect.apighana.com/api/data/districts/export?format=csv" \ -H "X-API-Key: $APIGHANA_KEY" \ -o districts.csv
id,name,region,boundary_id,area_sqkm,... 1,Adenta Municipal,Greater Accra Region,2480657B26321648161032,78.47,...
The rows matching a query, as a CSV or Excel file. Excel files carry an "About this data" sheet.
Path parameters
- tablestring
A dataset name from the catalogue, e.g.
districts,health_facilities,schools.
Body (JSON)
- formatstringdefault csv
csvorxlsx. - whereobject[]default []
As in POST /api/query/{table}.
INalso takes a comma-separated string here. - orderobject
{ column, direction }.
- The answer carries
X-Data-Source,X-Data-Last-UpdatedandX-Data-Coversheaders.
Errors
- 400 A bad body or an unknown column.
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
PLAN_REQUIREDNeeds the Business plan or higher. - 403
ACCESS_REQUIREDThe dataset is not on your key.data.optionssays how to get it: a yearly licence, a free pick, a pack or a plan. - 404 No dataset by that name.
- 429 Over your plan's requests per minute. Wait for
Retry-Afterseconds.
curl -X POST "https://connect.apighana.com/api/query/districts/export" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "csv",
"where": [
{
"column": "region",
"operator": "=",
"value": "Upper West Region"
}
],
"order": {
"column": "name",
"direction": "asc"
}
}' \
-o districts.csvname,region,area_sqkm,... Wa East,Upper West Region,4325,...
Starts a CSV or Parquet export of market history or a whole dataset. We email a download link when it is ready; you can also poll the job.
Body (JSON)
- kindstringdefault market
marketordataset. - formatstringdefault csv
csvorparquet. - groupsstring[]
For
market: any offx,fuel,banks,commodities,food,macro. Leave out for all. - fromstring
For
market: start date,YYYY-MM-DD. - tostring
For
market: end date,YYYY-MM-DD. - tablestring
For
dataset: the dataset name.
Errors
- 400 A bad body (
BAD_PARAMS). - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
PLAN_REQUIREDNeeds the Business plan or higher. - 429
TOO_MANYThree exports are already running.
curl -X POST "https://connect.apighana.com/api/market/exports" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "market",
"format": "csv",
"groups": [
"fx",
"fuel"
],
"from": "2026-01-01",
"to": "2026-09-24"
}'{
"status": "success",
"message": "Export queued. You will get an email with the link.",
"data": {
"id": 41,
"kind": "market",
"params": {
"groups": [
"fx",
"fuel"
],
"from": "2026-01-01",
"to": "2026-09-24"
},
"format": "csv",
"status": "queued",
"rows": null,
"bytes": null,
"download_url": null,
"expires_at": null,
"error": null,
"created_at": "2026-09-25T09:00:00.000Z",
"finished_at": null
}
}Your export jobs, with their status and, once finished, a download link and when it expires.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
curl "https://connect.apighana.com/api/market/exports" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Your exports",
"data": [
{
"id": 41,
"kind": "market",
"params": {
"groups": [
"fx",
"fuel"
],
"from": "2026-01-01",
"to": "2026-09-24"
},
"format": "csv",
"status": "done",
"rows": 5420,
"bytes": 318204,
"download_url": "https://…/exports/41.csv?token=…",
"expires_at": "2026-10-02T09:01:12.000Z",
"error": null,
"created_at": "2026-09-25T09:00:00.000Z",
"finished_at": "2026-09-25T09:01:12.000Z"
}
]
}One export job. Poll until status is done, then fetch download_url.
Path parameters
- idinteger
The job's
id.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 404 No export with that id on your account.
curl "https://connect.apighana.com/api/market/exports/41" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Export",
"data": {
"id": 41,
"kind": "market",
"params": {
"groups": [
"fx",
"fuel"
],
"from": "2026-01-01",
"to": "2026-09-24"
},
"format": "csv",
"status": "queued",
"rows": null,
"bytes": null,
"download_url": null,
"expires_at": null,
"error": null,
"created_at": "2026-09-25T09:00:00.000Z",
"finished_at": null
}
}Webhooks
We POST to your URL when a market group changes or news is published, instead of you polling. Webhooks come with the Business plan and up. Up to 10 endpoints per account.
| Event | When |
|---|---|
| rates.changed | Exchange rates changed. |
| fuel.changed | Fuel prices changed. |
| commodities.changed | Commodity prices changed. |
| food.changed | Food prices changed. |
| macro.changed | An economic indicator changed. |
| news.published | New stories were published. |
Each delivery is a POST of JSON with X-APIGhana-Event, X-APIGhana-Delivery (the event id), X-APIGhana-Timestamp (Unix seconds) and X-APIGhana-Signature headers. data.latest is where to read the new values. news.published carries the story instead: id, headline, url, source, category and published_at.
{
"id": "fx_2026-09-25T00",
"event": "rates.changed",
"created_at": "2026-09-25T00:00:05.000Z",
"data": {
"feed": "fx",
"series": 12,
"observations_new": 12,
"source_updated_at": "2026-09-25T00:00:01.000Z",
"latest": "https://connect.apighana.com/api/market/rates"
}
}Answer with any 2xx within 10 seconds. Anything else is retried after 1, 5, 30, 120 and 360 minutes and given up after 24 hours; an endpoint that fails 20 times in a row is switched off (turn it back on with active: true). The same event can arrive twice, so use X-APIGhana-Delivery to ignore repeats.
Check the signature before trusting a delivery: it is sha256= and the HMAC-SHA256, keyed with your endpoint's secret, of the timestamp, a dot and the raw body.
import crypto from "node:crypto";
// Use the raw request body, exactly as received.
function verify(req, rawBody, secret) {
const timestamp = req.headers["x-apighana-timestamp"];
const signature = req.headers["x-apighana-signature"];
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
return fresh && signature?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}Your webhook endpoints, the events you can subscribe to, and the last 30 deliveries.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
curl "https://connect.apighana.com/api/market/webhooks" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Webhook endpoints",
"data": {
"endpoints": [
{
"id": 7,
"url": "https://example.com/hooks/apighana",
"events": [
"rates.changed",
"fuel.changed"
],
"description": "Pricing service",
"active": true,
"created_at": "2026-09-25T09:00:00.000Z",
"failures": 0,
"last_delivery_at": "2026-09-25T08:00:03.000Z",
"last_status": 200,
"disabled_at": null
}
],
"events": [
"rates.changed",
"fuel.changed",
"commodities.changed",
"food.changed",
"macro.changed",
"news.published"
],
"deliveries": []
}
}Registers a URL for the events you choose. The answer includes the signing secret, shown only this once.
Body (JSON)
- urlstringrequired
A public
httpsURL. - eventsstring[]default ["rates.changed", "fuel.changed"]
Any of
rates.changed,fuel.changed,commodities.changed,food.changed,macro.changed,news.published. - descriptionstring
Up to 120 characters.
Errors
- 400
BAD_URLThe URL is not a public https address. - 400
BAD_EVENTSNo known event was chosen. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 403
PLAN_REQUIREDNeeds the Business plan or higher. - 429
TOO_MANYYou already have 10 endpoints.
curl -X POST "https://connect.apighana.com/api/market/webhooks" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/apighana",
"events": [
"rates.changed",
"fuel.changed"
],
"description": "Pricing service"
}'{
"status": "success",
"message": "Endpoint added. Keep the secret; it is shown once.",
"data": {
"id": 7,
"url": "https://example.com/hooks/apighana",
"events": [
"rates.changed",
"fuel.changed"
],
"description": "Pricing service",
"active": true,
"created_at": "2026-09-25T09:00:00.000Z",
"secret": "whsec_3f9c…"
}
}Changes the URL, events or description, or switches the endpoint off and on.
Path parameters
- idinteger
The endpoint's
id.
Body (JSON)
- urlstring
A public
httpsURL. - eventsstring[]
Replaces the list.
- descriptionstring
Up to 120 characters.
- activeboolean
falsestops deliveries;trueresumes them.
Errors
- 400
BAD_URLThe URL is not a public https address. - 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 404 No endpoint with that id on your account.
curl -X PATCH "https://connect.apighana.com/api/market/webhooks/7" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [
"rates.changed",
"fuel.changed",
"news.published"
],
"active": true
}'{
"status": "success",
"message": "Endpoint updated",
"data": {
"id": 7,
"url": "https://example.com/hooks/apighana",
"events": [
"rates.changed",
"fuel.changed",
"news.published"
],
"description": "Pricing service",
"active": true,
"created_at": "2026-09-25T09:00:00.000Z",
"failures": 0
}
}Removes the endpoint; nothing more is sent to it.
Path parameters
- idinteger
The endpoint's
id.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
curl -X DELETE "https://connect.apighana.com/api/market/webhooks/7" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Endpoint removed",
"data": null
}Sends a test event to this endpoint now, so you can check your receiver and its signature check.
Path parameters
- idinteger
The endpoint's
id.
Errors
- 401 No
X-API-Keyheader, or the key is wrong or revoked. - 403 The key is inactive or the account is deactivated.
- 404 No endpoint with that id on your account.
curl -X POST "https://connect.apighana.com/api/market/webhooks/7/test" \ -H "X-API-Key: $APIGHANA_KEY"
{
"status": "success",
"message": "Test delivery attempted",
"data": {
"delivered": 1,
"failed": 0,
"dead": 0
}
}Status and plans
Whether the API is up, and what each plan includes. All public.
Whether the API, the database, the live feeds and the daily dataset checks are working. The same data as the status page.
curl "https://connect.apighana.com/api/status"
{
"status": "success",
"message": "Status",
"data": {
"state": "operational",
"components": [
{
"name": "API",
"state": "operational"
},
{
"name": "Database",
"state": "operational",
"latency_ms": 181
},
{
"name": "Live data feeds",
"state": "operational"
},
{
"name": "Dataset checks",
"state": "operational"
}
],
"feeds": [
{
"feed": "fx",
"label": "Exchange rates",
"state": "operational",
"last_success_at": "2026-09-25T07:38:14.599+00:00"
}
],
"datasets": {
"checked": 284,
"ok": 162,
"warning": 120,
"error": 2,
"last_checked_at": "2026-09-25T02:17:54.612+00:00",
"state": "operational"
},
"checked_at": "2026-09-25T08:50:46.703Z"
}
}Answers 200 while the API process is running. For uptime monitors.
curl "https://connect.apighana.com/api/health"
{
"status": "success",
"message": "API Ghana is running",
"data": {
"uptime": 1182.66
}
}Like health, but also checks the database: 503 when it cannot be reached.
Errors
- 503 The database cannot be reached.
curl "https://connect.apighana.com/api/health/ready"
{
"status": "success",
"message": "API Ghana is ready",
"data": {
"database": "ok",
"database_ms": 172
}
}Every plan with its price and limits: requests per minute, rows per page, history, exports, webhooks, News API.
Query parameters
- currencystring
GHSorUSD. Chosen from your country when left out.
curl "https://connect.apighana.com/api/plans"
{
"status": "success",
"message": "Plans",
"data": {
"currency": "USD",
"tiers_enabled": true,
"vat_rate": 0.15,
"plans": [
{
"code": "developer",
"name": "Developer",
"currency": "USD",
"monthly": 19,
"annual": 190,
"rate_per_minute": 600,
"rows_per_page": 500,
"history_days": 90,
"catalogue": "all",
"free_dataset_limit": 0,
"exports": "none",
"webhooks": false,
"news_api": true,
"intraday": false,
"bank_rows": null,
"support": "Email, 3 business days",
"uptime_target": null,
"self_serve": true
}
]
}
}MCP
API Ghana is also an MCP server, so AI assistants (Claude, ChatGPT, Cursor and others) can search the catalogue, read rows and query datasets themselves. It speaks JSON-RPC over Streamable HTTP; most people point an MCP client at it rather than calling it by hand.
Add it to your client with your key. The tools are read-only and call this API with your key, so your plan's access and limits apply.
{
"mcpServers": {
"api-ghana": {
"type": "http",
"url": "https://connect.apighana.com/mcp",
"headers": {
"X-API-Key": "YOUR_API_KEY"
}
}
}
}| Tool | What it does |
|---|---|
| search_datasets | Find datasets by words. |
| describe_dataset | A dataset's columns, source and access rules. |
| get_rows | Rows of a dataset, paged, with filter and search. |
| query_dataset | Columns, operators and sorting in one call. |
| get_market | The latest value of every series in a market group. |
| get_series | One series with its history. |
| search_news | Recent stories (News API: Developer and up with a key). |
The tools the server offers. Stateless: no session to open first.
- Send the key as
X-API-Key, or asAuthorization: Bearer <key>for clients that only send that. Without a key, tools that read rows say how to get one.
curl -X POST "https://connect.apighana.com/mcp" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'event: message
data: {"result":{"tools":[{"name":"search_datasets","title":"Search Ghana datasets",…},{"name":"describe_dataset",…},{"name":"get_rows",…},{"name":"query_dataset",…},{"name":"get_market",…},{"name":"get_series",…},{"name":"search_news",…}]},"jsonrpc":"2.0","id":1}Runs one tool with your key; your plan's access and limits apply.
curl -X POST "https://connect.apighana.com/mcp" \
-H "X-API-Key: $APIGHANA_KEY" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_rows",
"arguments": {
"dataset": "districts",
"limit": 2
}
}
}'event: message
data: {"result":{"content":[{"type":"text","text":"{\"data\":[{\"id\":1,\"name\":\"Adenta Municipal\",…}],\"meta\":{…}}"}]},"jsonrpc":"2.0","id":2}Postman and OpenAPI
- Postman collection api-ghana.postman_collection.json
Every request on this page, in folders, with example answers. - Postman environment api-ghana.postman_environment.json
The base URL, a blank api_key and working defaults for the path variables. - OpenAPI 3 openapi.json
For client generators, Insomnia and other API tools.
- In Postman, choose Import and drop in both files.
- Choose the API Ghana environment (top right) and paste your key into
api_key. It is marked secret, so Postman hides it. - Send a request. Change
dataset,seriesormarket_groupin the environment to point every request at something else.
Questions, or a dataset you need: info@apighana.com.