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/sdkWorks 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/sdkRequires 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
