Ardent AfricaDocs
Developers

SDKs

Official typed, read-only client libraries for JavaScript/TypeScript and PHP.

We publish small, hand-written, read-only client libraries so you don't have to hand-roll fetch/cURL calls. They wrap the public API (/public/v1), carry the optional x-api-key header, and surface the error envelope as a typed exception. No write access, no PII.

Both mirror the published OpenAPI contract and follow the same versioning policy. Treat response objects as open (new fields may be added within v1).

JavaScript / TypeScript

npm install @ardent-africa/sdk

Works in Node 18+ and modern browsers (uses the global fetch).

import { ArdentClient, ArdentApiError } from '@ardent-africa/sdk';

// The key is optional (keyless works at a lower rate tier).
const ardent = new ArdentClient({ apiKey: process.env.ARDENT_API_KEY });

const { data, total } = await ardent.listCampaigns({ limit: 5, category: 'Education' });
const campaign = await ardent.getCampaign('clean-water-for-tamale');
const stats = await ardent.getStats();

try {
  await ardent.getCampaign('does-not-exist');
} catch (err) {
  if (err instanceof ArdentApiError && err.code === 'NOT_FOUND') {
    // err.code, err.message, err.status, err.ref
  }
}

Every response is fully typed. List methods return { data, page, limit, total }.

PHP

composer require ardent-africa/sdk

Requires PHP 7.4+ (ext-curl, ext-json only: no third-party packages).

use Ardent\Sdk\Client;
use Ardent\Sdk\ArdentApiException;

$ardent = new Client(['api_key' => getenv('ARDENT_API_KEY')]);

$page = $ardent->listCampaigns(['limit' => 5, 'category' => 'Education']);
foreach ($page['data'] as $campaign) {
    echo $campaign['title'], "\n";
}

try {
    $ardent->getCampaign('does-not-exist');
} catch (ArdentApiException $e) {
    // $e->apiCode, $e->getMessage(), $e->httpStatus, $e->ref
}

Methods return the decoded JSON as associative arrays.

Methods

Both SDKs expose the same surface:

listCampaigns · getCampaign · listPetitions · getPetition · listEvents · getEvent · listJobs · getJob · listSurveys · getSurvey · listDurbars · getDurbar · getDurbarTranscript · listReviewEntities · getReviewEntity · listActors · getActor · listPosts · getPost · listGroups · getGroup · listServices · getService · listCategories · listBlog · getBlogPost · getProfile · getStats.

listSurveys and getSurvey return what a survey asks and how many people answered, never an individual response. On an anonymous survey an individual response does not exist to be returned: nothing is stored linking one to a person. response_count is number | null, and the null matters: a survey that does not publish its results yet returns null rather than 0, because zero would be a claim that nobody has answered. Check results_revealed first.

listDurbars returns public live audio rooms only. An unlisted durbar stays reachable through getDurbar by slug, because that is what its host shared, and is absent from the index, because an index any key can page through would publish every one of them at once. peak_listener_count and total_listeners are number | null, and here the null means something different from the survey case: counts are published for ended rooms only. A live room's peak moves, and a figure that drops when somebody refreshes reads as a room emptying out.

Speakers are named; listeners never are, at any tier. getDurbarTranscript returns machine transcription of multi-speaker Ghanaian English that code-switches into Twi, Ga, Ewe and Pidgin, so names and switched passages are frequently wrong. Every segment carries a confidence, the response carries a disclaimer worth surfacing wherever you show the text, and segments carry no speaker at all, permanently: attribution would need diarisation, which is a guess. Neither SDK can join a room, and neither ever will.

listPosts returns only posts whose author chose a public audience. Anything limited to followers, to connections, or to a group is absent whoever is asking, so a list of one author's posts is a partial view of their activity by design. listGroups returns public communities only and never a member list.

Prefer to generate your own?

The OpenAPI spec lets you generate a client in any language. The official SDKs exist for the two ecosystems most of our integrators use (the WordPress plugin builds on the same patterns as the PHP client).

Community hazards

Both SDKs expose listHazards and getHazard. They are read-only, like everything else here, and there is deliberately no way to file a report or confirm somebody else's: both stay with a person, who is shown the emergency number first.

const { data, disclaimer } = await ardent.listHazards({ district_id: '...' });

for (const hazard of data) {
  console.log(hazard.title);
  // Show this. Most reports are unverified community reports.
  console.log(hazard.verification_note);
}

console.log(disclaimer.message); // Ardent is not an emergency service...

Note that these two methods return the whole envelope rather than a bare array, which is the one place the SDKs break their own pattern. The disclaimer sits on the envelope so that an empty result still carries it: a caller who queried a district and got nothing back is still building something about danger, and that is exactly when somebody writes their own "all clear" line.

getHazard throws not_found for a case that has been resolved, withdrawn or has expired. Treat that as "no longer current", not as an error, and stop showing anything you cached.

Last updated: 24 August 2026

On this page