Version: 1.0 Last Updated: August 2026 Status: Specification Published — Implementation Status Marked Per Endpoint
CeloHT is an open-source, community-governed initiative built on the Celo blockchain, focused on financial inclusion education, a community Agent Network, and environmental reforestation. This document specifies the CeloHT API: its design principles, authentication model, conventions, and endpoints.
CeloHT is not a cryptocurrency, ICO, token sale, or investment platform. No endpoint in this specification issues, sells, or trades a token or security. Endpoints referencing cUSD or CELO expose read access to existing, independently issued Celo-network assets used strictly as payment and settlement infrastructure — never a CeloHT-issued instrument.
As of this document's publication date, CeloHT's backend infrastructure is in early development. Every endpoint below is explicitly labeled Implemented, In Development, or Planned. Endpoints marked Planned describe designed-but-unbuilt functionality and are published so that integrating partners and contributors can build against a stable, forward-looking contract. No endpoint's status label should be read as a claim that the underlying functionality is live unless labeled Implemented.
- Introduction
- Architecture
- Base URL
- Authentication
- Authorization
- Headers
- Content Types
- Versioning Policy
- Rate Limits
- Pagination
- Filtering, Sorting, and Search
- Error Handling
- HTTP Status Codes
- Security
- Endpoints
- Response Standards
- Error Response Standards
- API Conventions
- Webhooks (Future)
- SDK Roadmap
- OpenAPI 3.1 Specification
- Postman Collection
- Developer Quick Start
- Testing
- Monitoring
- Changelog
- Deprecation Policy
- API Lifecycle
- Best Practices
- FAQ
- Support
- License
The CeloHT API exposes CeloHT's public-good data — education content, Agent Network information, reforestation impact records, and transparency reporting — and, where authenticated, supports user- and agent-facing actions such as wallet connection and donation processing. It exists to let the CeloHT dApp, community-built tools, partner integrations, and the public Impact Dashboard read from a single, consistent, well-governed source of truth.
- Core and community developers contributing to the CeloHT dApp (
ARCHITECTURE.mdSection 4). - Third-party developers building tools or integrations on top of CeloHT's public data.
- Ecosystem partners (NGOs, universities, grant programs) consuming impact and transparency data for due diligence.
- Internal services (analytics engine, indexer) described in
ARCHITECTURE.mdSection 5.
- Read access is public by default. Impact, education, and reforestation data are designed to be openly queryable, consistent with CeloHT's Transparency Policy (
GOVERNANCE.mdSection 18). - Write access is minimal and purposeful. Only actions with a genuine need for server-side coordination (donation processing, wallet linkage) require authenticated write endpoints; CeloHT does not build API surface area for its own sake.
- No token, no trading, no custody. The API never exposes an endpoint to issue, buy, sell, or trade a token, consistent with
LEGAL_STATUS.mdandNO_TOKEN_POLICY.md. - Honesty about implementation status. Every endpoint is labeled with its real build status, never presented as live before it is.
The CeloHT API follows REST conventions: resources are addressed by URL, standard HTTP methods express intent (GET, POST, PATCH, DELETE), and responses use standard HTTP status codes combined with a consistent JSON envelope (Section 16).
| Goal | How It's Achieved |
|---|---|
| Predictability | Consistent response envelope, consistent error format, documented conventions (Section 18) |
| Transparency-first | Public read endpoints require no authentication wherever data sensitivity allows |
| Security by default | HTTPS-only, JWT and wallet-signature authentication, input validation (Section 14) |
| Extensibility | Versioned base URL, additive-first change policy (Section 27) |
| Low integration friction | OpenAPI 3.1 specification (Section 21), Postman collection (Section 22), multi-language examples |
The CeloHT API is a stateless REST API, consistent with the Backend Architecture described in ARCHITECTURE.md Section 5.
- REST — Resources are nouns (
/education,/agents,/reforestation); actions are expressed through HTTP methods, not verbs in the URL. - Stateless requests — Each request carries all information needed to process it (authentication token, parameters); the server holds no client session state between requests.
- JSON responses — All responses are
application/json(Section 7), following the response envelope in Section 16. - HTTPS only — Plain HTTP requests are rejected; see Section 14.1.
- Versioning strategy — The API is versioned in the URL path (
/v1), described fully in Section 8.
graph TD
Client[dApp / Partner Integration / Indexer] -->|HTTPS + JSON| Gateway[API Gateway]
Gateway --> Auth[Auth Middleware<br/>JWT / Wallet Signature]
Auth --> Router[Resource Router]
Router --> EduSvc[Education Service]
Router --> AgentSvc[Agent Service]
Router --> ImpactSvc[Impact / Reforestation Service]
Router --> DonationSvc[Donation Service]
Router --> WalletSvc[Wallet Service]
EduSvc --> DB[(Database Layer)]
AgentSvc --> DB
ImpactSvc --> DB
DonationSvc --> DB
ImpactSvc --> Indexer[Blockchain Indexer]
Indexer --> Chain[(Celo Blockchain)]
https://api.celoht.org/v1
This URL is a placeholder consistent with CeloHT's expected production domain. As of this document's publication date, this base URL is Planned; no production API is confirmed live at this address. Developers should treat this base URL as the target contract for integration and confirm current availability through CeloHT's official GitHub organization before building against it in production.
A staging base URL, once available, will be published in ARCHITECTURE.md Section 14 and referenced from this document.
| Method | Use Case | Status |
|---|---|---|
| JWT Authentication | Standard authenticated requests (donation history, agent dashboard) | Planned |
| Wallet Signature Authentication | Actions tied to on-chain identity (wallet linkage, agent verification) | Planned |
| API Keys | Server-to-server integration for trusted partners | Planned |
| OAuth 2.0 | Third-party application authorization | Future |
Authenticated requests include a bearer token issued after a successful login or wallet-signature exchange:
Authorization: Bearer <jwt_token>
JWTs are short-lived (target: 15 minutes access token, 7-day refresh token) and signed using an asymmetric algorithm (RS256), consistent with OWASP API Security guidance (Section 14.9).
For actions tied to on-chain identity (e.g., linking a Valora or MiniPay wallet, verifying agent status), the client signs a server-issued challenge message using the connected wallet, and the API verifies the signature against the claimed address before issuing a session JWT.
sequenceDiagram
participant Client
participant API as CeloHT API
participant Wallet
Client->>API: POST /wallet/connect (address)
API-->>Client: Challenge nonce
Client->>Wallet: Request signature over nonce
Wallet-->>Client: Signed message
Client->>API: POST /wallet/sign (signature)
API->>API: Verify signature against address
API-->>Client: JWT (access + refresh token)
Planned. Server-to-server integrations (for example, a partner NGO's reporting system) will authenticate using a scoped API key issued by the Governance Council's Technology Working Group, transmitted via the X-API-Key header.
Future. OAuth 2.0 authorization-code flow is under consideration for third-party applications requiring delegated, user-consented access, and is not yet designed in detail.
- Client authenticates via wallet signature (Section 4.2) or, where applicable, a future username/credential flow.
- API issues a short-lived JWT access token and a longer-lived refresh token.
- Client includes the access token in the
Authorizationheader on subsequent requests. - Client exchanges the refresh token for a new access token upon expiry via the token-refresh endpoint (Planned).
Authorization is role-based, mirroring the roles defined in GOVERNANCE.md Section 3 and TEAM.md.
| Role | Example Permissions |
|---|---|
| Public (unauthenticated) | Read access to /education, /impact, /reforestation, /partners, /news, /health, /version |
| Learner | Read own education progress; enroll in courses |
| Donor | Submit donations; read own donation history |
| Agent | Submit cash-in/cash-out transaction records within verified scope |
| Maintainer / Working Group | Access to internal metrics and moderation endpoints |
| Governance Council / Treasury Committee | Access to treasury-adjacent internal endpoints (not part of the public API surface) |
Authorization checks are enforced server-side on every request; a valid JWT alone does not grant access beyond the roles encoded in its claims.
| Header | Required | Description |
|---|---|---|
Authorization |
For authenticated endpoints | Bearer <jwt_token> |
Content-Type |
For requests with a body | application/json |
Accept |
Recommended | application/json |
X-API-Key |
For server-to-server integrations (Planned) | Partner-issued API key |
X-Request-ID |
Optional, recommended | Client-generated UUID for request tracing |
Accept-Language |
Optional | ht (Haitian Creole) or en, for content localization where applicable |
The API exclusively accepts and returns application/json. Requests with an unsupported Content-Type receive a 415 Unsupported Media Type response (Planned enforcement).
- The API is versioned via the URL path:
/v1,/v2, etc. - Breaking changes are introduced only in a new major version; non-breaking (additive) changes may be introduced within the current version.
- A minimum 6-month deprecation notice is provided before a version is retired, consistent with Section 27.
- The currently active version and any deprecation notices are published via
GET /version(Section 15).
| Tier | Limit (Planned) | Notes |
|---|---|---|
| Unauthenticated (public read) | 60 requests/minute per IP | Applies to public endpoints |
| Authenticated (JWT) | 300 requests/minute per user | Applies to authenticated endpoints |
| Partner API Key | Negotiated per partnership agreement | Per PARTNERSHIP governance (GOVERNANCE.md Section 19) |
- Rate-limit status is communicated via standard headers:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset. - Exceeding a rate limit returns
429 Too Many Requestswith aRetry-Afterheader. - Retry policy: clients should implement exponential backoff starting at 1 second, honoring the
Retry-Afterheader where present.
Specific numeric limits above are the current design target and are subject to adjustment before general availability; the mechanism (headers, 429 response, Retry-After) is stable.
List endpoints use cursor-based pagination for stability under concurrent writes:
Request:
GET /v1/education/courses?limit=20&cursor=eyJpZCI6IjEyMyJ9
Response fragment:
{
"data": [ ... ],
"pagination": {
"limit": 20,
"next_cursor": "eyJpZCI6IjE0MyJ9",
"has_more": true
}
}| Parameter | Type | Description |
|---|---|---|
limit |
integer | Items per page (default 20, max 100) |
cursor |
string | Opaque cursor returned by the previous response |
List endpoints support field-based filtering via query parameters, e.g.:
GET /v1/reforestation/trees?status=verified®ion=leogane
GET /v1/education/courses?sort=created_at&order=desc
| Parameter | Description |
|---|---|
sort |
Field to sort by |
order |
asc or desc (default asc) |
Endpoints supporting free-text search accept a q parameter:
GET /v1/education/courses?q=cUSD+basics
Search behavior (exact-match vs. full-text) is documented per endpoint in Section 15.
All errors return a consistent JSON error object (Section 17) alongside the appropriate HTTP status code (Section 13). Clients should branch on the HTTP status code first and use the error code field for programmatic handling of specific conditions.
| Code | Meaning | Usage in CeloHT API |
|---|---|---|
200 OK |
Success | Successful GET, PATCH |
201 Created |
Resource created | Successful POST creating a resource (e.g., a donation record) |
204 No Content |
Success, no response body | Successful DELETE or action with no return payload |
400 Bad Request |
Malformed request | Invalid JSON, missing required field |
401 Unauthorized |
Missing or invalid authentication | Missing/expired JWT, invalid signature |
403 Forbidden |
Authenticated but not permitted | Valid JWT, insufficient role |
404 Not Found |
Resource does not exist | Invalid resource ID |
409 Conflict |
State conflict | Duplicate wallet linkage, concurrent update conflict |
422 Unprocessable Entity |
Semantically invalid request | Valid JSON, fails business-rule validation |
429 Too Many Requests |
Rate limit exceeded | See Section 9 |
500 Internal Server Error |
Unhandled server error | Logged and monitored per Section 25 |
503 Service Unavailable |
Service temporarily unavailable | Planned maintenance, dependency outage |
CeloHT's API security approach follows the principles in ARCHITECTURE.md Section 12 and the OWASP API Security Top 10.
All traffic is served exclusively over HTTPS (TLS 1.2+). Plain HTTP requests are redirected or rejected, never processed.
All request bodies and parameters are validated against a defined schema (JSON Schema, derived from the OpenAPI specification in Section 21) before processing; invalid input returns 400 or 422 with a specific error code.
See Section 9. Rate limiting mitigates abuse and brute-force authentication attempts, consistent with OWASP API4:2023 (Unrestricted Resource Consumption).
Wallet-signature authentication (Section 4.2) verifies the cryptographic signature against the claimed address server-side before issuing any session token; a mismatched or malformed signature is rejected with 401.
JWTs are validated for signature integrity, expiry, issuer, and audience claims on every authenticated request. Expired or tampered tokens are rejected with 401.
Wallet-signature challenges (Section 4.2) are single-use, time-limited nonces; a previously used nonce is rejected, mitigating replay attacks.
Cross-Origin Resource Sharing is restricted to an explicit allow-list of CeloHT-controlled and approved partner domains, configured server-side rather than allowing wildcard origins for authenticated endpoints.
The API design targets alignment with the OWASP API Security Top 10, including broken object-level authorization (API1), broken authentication (API2), broken object property-level authorization (API3), unrestricted resource consumption (API4), and security misconfiguration (API8), addressed through the authorization model (Section 5), authentication design (Section 4), rate limiting (Section 9), and input validation (Section 14.2).
API signing keys, database credentials, and partner API keys are stored in a dedicated secrets-management system, never committed to source control, consistent with ARCHITECTURE.md Section 12.5 (CI/CD Pipeline) secret-scanning practices.
Requests are logged with a request ID, timestamp, endpoint, status code, and latency; authentication and authorization failures are logged with additional detail sufficient for incident investigation, excluding sensitive payload content.
See Section 25.
Each endpoint below documents its current implementation status. Full request/response detail and a subset of language examples are provided for every endpoint; representative endpoints include the complete multi-language example set described in Section 23. Additional language examples follow the same pattern documented there.
Status: Planned
| Field | Detail |
|---|---|
| Purpose | Liveness check for load balancers and monitoring |
| Method / URL | GET /v1/health |
| Description | Returns a minimal payload confirming the API process is running |
| Authentication | None |
| Parameters | None |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"status": "ok",
"timestamp": "2026-08-04T12:00:00Z"
}Error Response — 503 Service Unavailable
{
"error": {
"code": "service_unavailable",
"message": "The service is temporarily unavailable.",
"request_id": "b3f1e2a4-...-000"
}
}cURL
curl -s https://api.celoht.org/v1/healthJavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/health");
const data = await res.json();
console.log(data.status);TypeScript
interface HealthResponse {
status: "ok" | "degraded";
timestamp: string;
}
const res = await fetch("https://api.celoht.org/v1/health");
const data: HealthResponse = await res.json();Python
import requests
response = requests.get("https://api.celoht.org/v1/health")
data = response.json()
print(data["status"])Flutter / Dart
final response = await http.get(Uri.parse('https://api.celoht.org/v1/health'));
final data = jsonDecode(response.body);
print(data['status']);Status: Planned
| Field | Detail |
|---|---|
| Purpose | Expose aggregate, non-identifying platform metrics for internal monitoring and the public Impact Dashboard |
| Method / URL | GET /v1/metrics |
| Description | Returns aggregate counts (learners reached, agents active, trees planted) consistent with ARCHITECTURE.md Section 13.3 |
| Authentication | None for public aggregate metrics; internal operational metrics require Maintainer-level JWT |
| Parameters | scope (optional): public (default) or internal |
| Headers | Authorization required only for scope=internal |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"learners_reached": null,
"agents_active": null,
"trees_planted": null,
"as_of": "2026-08-04T00:00:00Z"
},
"meta": {
"note": "Not Yet Available — reporting pipeline pending activation"
}
}Error Response — 403 Forbidden
{
"error": {
"code": "insufficient_scope",
"message": "Internal metrics require a Maintainer-level token.",
"request_id": "b3f1e2a4-...-001"
}
}cURL
curl -s https://api.celoht.org/v1/metricsJavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/metrics");
const { data } = await res.json();Status: Planned
| Field | Detail |
|---|---|
| Purpose | Return aggregated impact data across all three pillars for the public Impact Dashboard |
| Method / URL | GET /v1/impact |
| Description | Aggregates data from Education, Agent Network, and Reforestation services per ARCHITECTURE.md Section 13.3 |
| Authentication | None |
| Parameters | period (optional): all_time (default), year, quarter, month |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"period": "all_time",
"education": { "learners": null, "courses_completed": null },
"agent_network": { "agents_active": null, "transactions_facilitated": null },
"reforestation": { "trees_planted": null, "sites_active": null }
}
}cURL
curl -s "https://api.celoht.org/v1/impact?period=quarter"Python
import requests
response = requests.get("https://api.celoht.org/v1/impact", params={"period": "quarter"})
print(response.json())Status: Planned
| Field | Detail |
|---|---|
| Purpose | Return the Education pillar's program overview and category listing |
| Method / URL | GET /v1/education |
| Description | Top-level entry point for the Education pillar; links to /education/courses |
| Authentication | None |
| Parameters | None |
| Headers | Accept-Language optional |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"pillar": "education",
"description": "Web3, financial literacy, and digital-skills education.",
"categories": ["web3-basics", "financial-literacy", "cusd-valora-training", "digital-skills"]
}
}cURL
curl -s https://api.celoht.org/v1/educationStatus: Planned
| Field | Detail |
|---|---|
| Purpose | List available education courses/modules |
| Method / URL | GET /v1/education/courses |
| Description | Supports pagination, filtering, sorting, and search per Sections 10–11 |
| Authentication | None for listing; Authorization required to view personal enrollment status |
| Parameters | category, language, q, sort, order, limit, cursor |
| Headers | Authorization optional |
| Request Body | None |
Success Response — 200 OK
{
"data": [
{
"id": "crs_01HXAMPLE",
"title": "Introduction to cUSD and Valora",
"category": "cusd-valora-training",
"language": "ht",
"duration_minutes": 45
}
],
"pagination": { "limit": 20, "next_cursor": null, "has_more": false }
}Error Response — 400 Bad Request
{
"error": {
"code": "invalid_parameter",
"message": "The 'limit' parameter must be between 1 and 100.",
"request_id": "b3f1e2a4-...-002"
}
}cURL
curl -s "https://api.celoht.org/v1/education/courses?category=cusd-valora-training&limit=10"JavaScript (Fetch)
const res = await fetch(
"https://api.celoht.org/v1/education/courses?category=cusd-valora-training&limit=10"
);
const { data } = await res.json();TypeScript
interface Course {
id: string;
title: string;
category: string;
language: "ht" | "en";
duration_minutes: number;
}
const res = await fetch("https://api.celoht.org/v1/education/courses");
const { data }: { data: Course[] } = await res.json();Python
import requests
response = requests.get(
"https://api.celoht.org/v1/education/courses",
params={"category": "cusd-valora-training", "limit": 10},
)
courses = response.json()["data"]Flutter / Dart
final uri = Uri.parse('https://api.celoht.org/v1/education/courses')
.replace(queryParameters: {'category': 'cusd-valora-training', 'limit': '10'});
final response = await http.get(uri);
final courses = jsonDecode(response.body)['data'];Status: Planned
| Field | Detail |
|---|---|
| Purpose | List verified Agent Network participants (public, non-identifying summary) |
| Method / URL | GET /v1/agents |
| Description | Returns public agent summary data consistent with ARCHITECTURE.md Section 8; does not expose personal identity data |
| Authentication | None for public listing; Authorization required for full agent profile access |
| Parameters | region, status (verified, pending), limit, cursor |
| Headers | None required for public access |
| Request Body | None |
Success Response — 200 OK
{
"data": [
{
"agent_id": "agt_01HXAMPLE",
"region": "leogane",
"status": "verified",
"on_chain_registry_ref": "0xExampleTxHash"
}
],
"pagination": { "limit": 20, "next_cursor": null, "has_more": false }
}cURL
curl -s "https://api.celoht.org/v1/agents?region=leogane&status=verified"Status: Planned
| Field | Detail |
|---|---|
| Purpose | List communities CeloHT operates in or partners with |
| Method / URL | GET /v1/communities |
| Description | Returns community metadata (region, active pillars, contact channel) |
| Authentication | None |
| Parameters | region, limit, cursor |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": [
{
"community_id": "cmt_01HXAMPLE",
"region": "leogane",
"active_pillars": ["education", "agent_network"]
}
]
}cURL
curl -s https://api.celoht.org/v1/communitiesStatus: Planned
| Field | Detail |
|---|---|
| Purpose | Return the Reforestation pillar's program overview |
| Method / URL | GET /v1/reforestation |
| Description | Top-level entry point for the Reforestation pillar; links to /reforestation/trees |
| Authentication | None |
| Parameters | None |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"pillar": "reforestation",
"description": "Tree planting and environmental impact tracking.",
"active_sites": null
}
}cURL
curl -s https://api.celoht.org/v1/reforestationStatus: Planned
| Field | Detail |
|---|---|
| Purpose | List individual or aggregated tree-planting records with verification status |
| Method / URL | GET /v1/reforestation/trees |
| Description | Returns records anchored to on-chain attestation hashes per ARCHITECTURE.md Section 10.2 |
| Authentication | None |
| Parameters | region, status (verified, pending), species, limit, cursor |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": [
{
"record_id": "tre_01HXAMPLE",
"region": "leogane",
"species": "example_species",
"quantity": 0,
"status": "pending",
"attestation_hash": null
}
]
}cURL
curl -s "https://api.celoht.org/v1/reforestation/trees?region=leogane&status=verified"JavaScript (Fetch)
const res = await fetch(
"https://api.celoht.org/v1/reforestation/trees?status=verified"
);
const { data } = await res.json();Status: Planned
| Field | Detail |
|---|---|
| Purpose | List publicly disclosed CeloHT partnerships |
| Method / URL | GET /v1/partners |
| Description | Reflects partnerships approved per GOVERNANCE.md Section 19 |
| Authentication | None |
| Parameters | type (ngo, university, grant_program, ecosystem), limit, cursor |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": []
}cURL
curl -s https://api.celoht.org/v1/partnersStatus: Planned
| Field | Detail |
|---|---|
| Purpose | List upcoming and past CeloHT community events (workshops, planting days) |
| Method / URL | GET /v1/events |
| Description | Returns event metadata; supports filtering by pillar and time range |
| Authentication | None |
| Parameters | pillar, from, to, limit, cursor |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": []
}cURL
curl -s "https://api.celoht.org/v1/events?pillar=education"Status: Planned
| Field | Detail |
|---|---|
| Purpose | List official CeloHT announcements and published updates |
| Method / URL | GET /v1/news |
| Description | Mirrors release notes and governance announcements per GOVERNANCE.md Section 18.5 |
| Authentication | None |
| Parameters | limit, cursor |
| Headers | Accept-Language optional |
| Request Body | None |
Success Response — 200 OK
{
"data": []
}cURL
curl -s https://api.celoht.org/v1/newsStatus: Planned
| Field | Detail |
|---|---|
| Purpose | Return the authenticated user's or agent's cUSD transaction history facilitated through CeloHT |
| Method / URL | GET /v1/transactions |
| Description | Returns off-chain records reconciled with on-chain data per ARCHITECTURE.md Section 6.5. Does not expose other users' transaction data. |
| Authentication | Required (JWT) |
| Parameters | from, to, limit, cursor |
| Headers | Authorization required |
| Request Body | None |
Success Response — 200 OK
{
"data": [
{
"transaction_id": "txn_01HXAMPLE",
"type": "cash_in",
"amount_cusd": "0.00",
"on_chain_tx_hash": null,
"status": "pending"
}
]
}Error Response — 401 Unauthorized
{
"error": {
"code": "unauthorized",
"message": "A valid access token is required.",
"request_id": "b3f1e2a4-...-003"
}
}cURL
curl -s -H "Authorization: Bearer <jwt_token>" \
https://api.celoht.org/v1/transactionsJavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/transactions", {
headers: { Authorization: `Bearer ${jwtToken}` },
});
const { data } = await res.json();Status: Planned
| Field | Detail |
|---|---|
| Purpose | Return aggregate, non-identifying donation activity, or the authenticated donor's own donation history |
| Method / URL | GET /v1/donations |
| Description | Public scope returns aggregate totals per DONATION_POLICY.md Section 5; authenticated scope returns the caller's own donation records only |
| Authentication | None for aggregate scope; JWT required for personal donation history |
| Parameters | scope (aggregate default, personal), period, limit, cursor |
| Headers | Authorization required for scope=personal |
| Request Body | None |
Success Response — 200 OK (aggregate scope)
{
"data": {
"scope": "aggregate",
"period": "all_time",
"total_donations": null,
"note": "Not Yet Available"
}
}cURL
curl -s "https://api.celoht.org/v1/donations?scope=aggregate"Status: Planned
| Field | Detail |
|---|---|
| Purpose | Record a donation intent, consistent with DONATION_POLICY.md |
| Method / URL | POST /v1/donations |
| Description | Creates a pending donation record; actual value transfer occurs via the donor's wallet on the Celo blockchain, not custodially through this API |
| Authentication | Required (JWT) for a personally attributed donation; anonymous donations follow the review process in DONATION_POLICY.md Section 1 |
| Parameters | None |
| Headers | Authorization (if attributed), Content-Type: application/json |
| Request Body | See below |
Request Body
{
"amount_cusd": "10.00",
"restriction": "reforestation",
"anonymous": false
}| Field | Type | Required | Description |
|---|---|---|---|
amount_cusd |
string (decimal) | Yes | Intended donation amount in cUSD |
restriction |
string | null | No | One of the categories in TREASURY.md Section 6, or null for unrestricted |
anonymous |
boolean | No | Whether the donor requests anonymity per DONATION_POLICY.md Section 6 |
Success Response — 201 Created
{
"data": {
"donation_id": "don_01HXAMPLE",
"status": "pending_on_chain_confirmation",
"amount_cusd": "10.00",
"restriction": "reforestation",
"created_at": "2026-08-04T12:00:00Z"
}
}Error Response — 422 Unprocessable Entity
{
"error": {
"code": "invalid_restriction",
"message": "The requested restriction could not be honored per DONATION_POLICY.md Section 2.",
"request_id": "b3f1e2a4-...-004"
}
}cURL
curl -s -X POST https://api.celoht.org/v1/donations \
-H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
-d '{"amount_cusd": "10.00", "restriction": "reforestation", "anonymous": false}'JavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/donations", {
method: "POST",
headers: {
Authorization: `Bearer ${jwtToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount_cusd: "10.00",
restriction: "reforestation",
anonymous: false,
}),
});
const { data } = await res.json();TypeScript
interface DonationRequest {
amount_cusd: string;
restriction?: string | null;
anonymous?: boolean;
}
interface DonationResponse {
donation_id: string;
status: string;
amount_cusd: string;
restriction: string | null;
created_at: string;
}
async function createDonation(
payload: DonationRequest,
jwtToken: string
): Promise<DonationResponse> {
const res = await fetch("https://api.celoht.org/v1/donations", {
method: "POST",
headers: {
Authorization: `Bearer ${jwtToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const { data } = await res.json();
return data;
}Python
import requests
response = requests.post(
"https://api.celoht.org/v1/donations",
headers={"Authorization": f"Bearer {jwt_token}"},
json={"amount_cusd": "10.00", "restriction": "reforestation", "anonymous": False},
)
donation = response.json()["data"]Flutter / Dart
final response = await http.post(
Uri.parse('https://api.celoht.org/v1/donations'),
headers: {
'Authorization': 'Bearer $jwtToken',
'Content-Type': 'application/json',
},
body: jsonEncode({
'amount_cusd': '10.00',
'restriction': 'reforestation',
'anonymous': false,
}),
);
final donation = jsonDecode(response.body)['data'];Status: Planned
| Field | Detail |
|---|---|
| Purpose | Initiate wallet-signature authentication by requesting a challenge nonce for a given address |
| Method / URL | POST /v1/wallet/connect |
| Description | First step of the flow in Section 4.2 |
| Authentication | None (this endpoint issues the challenge that authentication is built on) |
| Parameters | None |
| Headers | Content-Type: application/json |
| Request Body | See below |
Request Body
{
"address": "0xExampleCeloAddress",
"wallet_type": "valora"
}| Field | Type | Required | Description |
|---|---|---|---|
address |
string | Yes | Celo wallet address |
wallet_type |
string | Yes | valora, minipay, or walletconnect |
Success Response — 200 OK
{
"data": {
"challenge": "Sign this message to authenticate with CeloHT: 7f2c...nonce",
"expires_at": "2026-08-04T12:05:00Z"
}
}Error Response — 400 Bad Request
{
"error": {
"code": "invalid_address",
"message": "The provided address is not a valid Celo address.",
"request_id": "b3f1e2a4-...-005"
}
}cURL
curl -s -X POST https://api.celoht.org/v1/wallet/connect \
-H "Content-Type: application/json" \
-d '{"address": "0xExampleCeloAddress", "wallet_type": "valora"}'JavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/wallet/connect", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ address, wallet_type: "valora" }),
});
const { data } = await res.json();Status: Planned
| Field | Detail |
|---|---|
| Purpose | Complete wallet-signature authentication by submitting the signed challenge |
| Method / URL | POST /v1/wallet/sign |
| Description | Second step of the flow in Section 4.2; issues a session JWT on success |
| Authentication | None (this endpoint produces authentication) |
| Parameters | None |
| Headers | Content-Type: application/json |
| Request Body | See below |
Request Body
{
"address": "0xExampleCeloAddress",
"signature": "0xExampleSignature"
}Success Response — 200 OK
{
"data": {
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"expires_in": 900
}
}Error Response — 401 Unauthorized
{
"error": {
"code": "signature_verification_failed",
"message": "The provided signature does not match the claimed address.",
"request_id": "b3f1e2a4-...-006"
}
}cURL
curl -s -X POST https://api.celoht.org/v1/wallet/sign \
-H "Content-Type: application/json" \
-d '{"address": "0xExampleCeloAddress", "signature": "0xExampleSignature"}'JavaScript (Fetch)
const res = await fetch("https://api.celoht.org/v1/wallet/sign", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ address, signature }),
});
const { data } = await res.json();Python
import requests
response = requests.post(
"https://api.celoht.org/v1/wallet/sign",
json={"address": address, "signature": signature},
)
tokens = response.json()["data"]Status: Planned
| Field | Detail |
|---|---|
| Purpose | Return operational status of API subsystems (database, blockchain indexer, external dependencies) |
| Method / URL | GET /v1/system/status |
| Description | More detailed than /health; intended for status-page and monitoring integration |
| Authentication | None |
| Parameters | None |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"api": "operational",
"database": "operational",
"blockchain_indexer": "operational",
"checked_at": "2026-08-04T12:00:00Z"
}
}cURL
curl -s https://api.celoht.org/v1/system/statusStatus: Planned
| Field | Detail |
|---|---|
| Purpose | Return current API version and deprecation notices |
| Method / URL | GET /v1/version |
| Description | Supports client-side version-compatibility checks |
| Authentication | None |
| Parameters | None |
| Headers | None required |
| Request Body | None |
Success Response — 200 OK
{
"data": {
"current_version": "v1",
"supported_versions": ["v1"],
"deprecated_versions": []
}
}cURL
curl -s https://api.celoht.org/v1/versionAll successful responses use a consistent envelope:
{
"data": { },
"meta": { },
"pagination": { }
}| Field | Presence | Description |
|---|---|---|
data |
Always | The primary payload — an object or array |
meta |
Optional | Supplementary information (notices, counts) |
pagination |
List endpoints only | Pagination cursor and limit information (Section 10) |
All error responses use a consistent envelope:
{
"error": {
"code": "string_error_code",
"message": "Human-readable description of the error.",
"details": { },
"request_id": "uuid"
}
}| Field | Description |
|---|---|
code |
Stable, machine-readable error identifier (snake_case) |
message |
Human-readable explanation, safe to display to developers |
details |
Optional structured detail (e.g., field-level validation errors) |
request_id |
Correlates the error with server-side logs (Section 14.10) |
Example — field validation error:
{
"error": {
"code": "validation_failed",
"message": "One or more fields failed validation.",
"details": {
"amount_cusd": "Must be a positive decimal value."
},
"request_id": "b3f1e2a4-...-007"
}
}| Convention | Rule |
|---|---|
| Naming | snake_case for JSON fields; kebab-case for URL path segments |
| Dates | ISO 8601, UTC, e.g. 2026-08-04T12:00:00Z |
| Time zones | All timestamps are UTC; clients convert for local display |
| IDs | Prefixed, sortable identifiers, e.g. crs_01HXAMPLE, don_01HXAMPLE |
| UUIDs | Used for request_id and internal correlation identifiers |
| Booleans | true / false, never "true" / "false" strings |
| Null values | Explicit null for "not yet available," distinct from omitted fields |
| Enums | Lowercase snake_case string values, documented per field |
Status: Future — design only, not scheduled for near-term implementation.
Planned webhook events would notify partner systems of relevant state changes without polling:
| Event (Planned) | Trigger |
|---|---|
donation.confirmed |
An on-chain donation transaction is confirmed |
agent.verified |
An agent completes verification (ARCHITECTURE.md Section 8.2) |
reforestation.attested |
A reforestation report's on-chain attestation is confirmed |
Planned design principles: HMAC-signed payloads for authenticity verification, at-least-once delivery with idempotency keys, and a subscription management endpoint for partners. None of this is implemented as of this document's publication date.
| Language | Status |
|---|---|
| JavaScript | Planned |
| TypeScript | Planned |
| Python | Planned |
| Flutter / Dart | Planned |
| Go | Future |
| Rust | Future |
SDKs will wrap the endpoints in Section 15 with typed clients, automatic JWT refresh, and pagination helpers, once the underlying API reaches general availability. Until then, the code examples throughout Section 15 serve as the reference integration pattern.
A starter OpenAPI 3.1 specification, reflecting the endpoints in Section 15:
openapi: 3.1.0
info:
title: CeloHT API
version: "1.0.0"
description: >
Public and authenticated API for the CeloHT open-source financial
inclusion, education, and reforestation initiative. CeloHT is not a
cryptocurrency, token, or investment platform.
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0
servers:
- url: https://api.celoht.org/v1
description: Production (Planned)
paths:
/health:
get:
summary: Liveness check
operationId: getHealth
security: []
responses:
"200":
description: Service is healthy
content:
application/json:
schema:
$ref: "#/components/schemas/HealthResponse"
/education/courses:
get:
summary: List education courses
operationId: listCourses
security: []
parameters:
- name: category
in: query
schema: { type: string }
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
- name: cursor
in: query
schema: { type: string }
responses:
"200":
description: A paginated list of courses
content:
application/json:
schema:
$ref: "#/components/schemas/CourseListResponse"
/donations:
post:
summary: Create a donation intent
operationId: createDonation
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DonationRequest"
responses:
"201":
description: Donation intent created
content:
application/json:
schema:
$ref: "#/components/schemas/DonationResponse"
"422":
description: Validation error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/wallet/connect:
post:
summary: Request a wallet-signature challenge
operationId: connectWallet
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [address, wallet_type]
properties:
address: { type: string }
wallet_type:
type: string
enum: [valora, minipay, walletconnect]
responses:
"200":
description: Challenge issued
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
HealthResponse:
type: object
properties:
status: { type: string, enum: [ok, degraded] }
timestamp: { type: string, format: date-time }
Course:
type: object
properties:
id: { type: string }
title: { type: string }
category: { type: string }
language: { type: string, enum: [ht, en] }
duration_minutes: { type: integer }
CourseListResponse:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/Course"
pagination:
type: object
properties:
limit: { type: integer }
next_cursor: { type: [string, "null"] }
has_more: { type: boolean }
DonationRequest:
type: object
required: [amount_cusd]
properties:
amount_cusd: { type: string }
restriction: { type: [string, "null"] }
anonymous: { type: boolean, default: false }
DonationResponse:
type: object
properties:
data:
type: object
properties:
donation_id: { type: string }
status: { type: string }
amount_cusd: { type: string }
restriction: { type: [string, "null"] }
created_at: { type: string, format: date-time }
ErrorResponse:
type: object
properties:
error:
type: object
properties:
code: { type: string }
message: { type: string }
details: { type: object }
request_id: { type: string }This specification is a starting point covering a representative subset of endpoints; the complete specification, once finalized, will be published as openapi.yaml in the celoht-dapp or a dedicated API repository and kept in sync with this document.
Status: Planned. Once the OpenAPI specification (Section 21) is finalized and the API reaches an implemented state, CeloHT will publish a Postman collection generated directly from that specification, ensuring the collection never drifts from the documented contract.
Planned import steps:
- Download
celoht-api.postman_collection.jsonfrom theceloht-docsrepository (path to be published). - In Postman, select Import → File → choose the downloaded collection.
- Create a Postman Environment with variables
base_url(https://api.celoht.org/v1) andjwt_token. - Run the
wallet/connectandwallet/signrequests first to populatejwt_tokenfor authenticated requests.
- Read the docs. Review this document alongside
ARCHITECTURE.mdandGOVERNANCE.mdfor context on CeloHT's design principles. - Explore public endpoints. Public read endpoints (
/education,/impact,/reforestation) require no authentication — start there. - Set up wallet authentication. Follow the flow in Section 4.2 using a Valora, MiniPay, or WalletConnect-compatible wallet on Celo's test network once available.
- Follow the response envelope. Parse the
datafield consistently per Section 16; handle errors via theerror.codefield per Section 17. - Respect rate limits. Implement exponential backoff honoring
Retry-After(Section 9). - Check
/versionbefore integrating. Confirm current API version and any deprecation notices before building a production integration. - Watch the changelog. Track
CHANGELOG.mdin the API repository (Section 26) for updates as endpoints move from Planned to Implemented.
- Unit tests cover request validation, authorization logic, and response-formatting logic within each service module (
ARCHITECTURE.mdSection 5.1). - Integration tests exercise full request/response cycles against a test database and, for blockchain-dependent endpoints, a forked Celo testnet, consistent with
ARCHITECTURE.mdSection 14.3. - Contract tests validate that API responses conform to the OpenAPI specification (Section 21), preventing undocumented drift.
- A public sandbox/testnet environment is Planned and will be announced via
/versionand the project changelog once available.
| Area | Approach |
|---|---|
| Logging | Structured, per-request logs with request_id correlation (Section 14.10) |
| Metrics | Request rate, latency percentiles, and error rate per endpoint, feeding internal dashboards |
| Observability | Distributed tracing across API, database, and blockchain-indexer calls (Planned) |
| Health checks | /health (liveness) and /system/status (dependency status), per Sections 15.1 and 15.18 |
| Version | Date | Change |
|---|---|---|
| 1.0.0 | August 2026 | Initial publication of the CeloHT API specification. All endpoints marked Planned pending implementation. |
Future changes are logged here with a dated entry describing what changed, consistent with the Documentation Governance versioning practice in GOVERNANCE.md Section 14.3.
- A minimum 6-month notice is provided before any endpoint or API version is deprecated.
- Deprecated endpoints return a
Deprecationheader and, where applicable, aSunsetheader indicating the removal date, per common REST deprecation conventions. - Deprecation notices are published in this document's Changelog (Section 26) and via
GET /version. - Breaking changes are never introduced within an existing major version; they require a new version (Section 8).
flowchart LR
Design[Designed<br/>Documented in API.md] --> Planned[Planned<br/>Status: Planned]
Planned --> Dev[In Development]
Dev --> Implemented[Implemented<br/>Available in Production]
Implemented --> Deprecated[Deprecated<br/>Sunset Notice Issued]
Deprecated --> Removed[Removed]
Every endpoint in Section 15 currently sits at the Planned stage. As implementation proceeds, each endpoint's status label will be updated in place, with the change reflected in the Changelog (Section 26).
For integrators:
- Always check the
dataenvelope anderrorenvelope shape rather than assuming a specific HTTP status implies a specific payload shape. - Cache public, slow-changing data (e.g.,
/partners,/education) client-side where appropriate, respecting anyCache-Controlheaders once published. - Use idempotency keys (Planned support) for
POST /donationsto avoid duplicate donation records on retry. - Prefer cursor-based pagination (
cursor) over manual offset calculation for list endpoints.
For CeloHT contributors:
- Every new endpoint must be added to this document and the OpenAPI specification (Section 21) in the same pull request that implements it, consistent with
ARCHITECTURE.mdSection 12.4 (Code Review Policy). - No endpoint may be marked Implemented in this document until it is genuinely deployed and passing the tests described in Section 24.
Is the CeloHT API live today? No. As of this document's publication date, all endpoints are labeled Planned. This document specifies the target contract for integration.
Does the API let me buy or trade a CeloHT token?
No. CeloHT has no token. Endpoints referencing cUSD or CELO expose read access to existing Celo-network assets, never a CeloHT-issued instrument. See LEGAL_STATUS.md and NO_TOKEN_POLICY.md.
Can I get a full transaction history for any wallet?
No. GET /transactions returns only the authenticated caller's own records, consistent with data protection principles in LEGAL_STATUS.md Section 16.
How do I know which API version to use?
Check GET /version for the current and supported versions before integrating.
Where do I report a bug or request a feature?
Through the applicable CeloHT GitHub repository's issue tracker, following the contribution process in CONTRIBUTORS.md.
For API-related questions, open a GitHub Discussion or issue in the relevant CeloHT repository, consistent with GOVERNANCE.md Section 17. Security vulnerabilities should be reported through the responsible-disclosure process in GOVERNANCE.md Section 12.1, not through a public issue.
This API specification and the CeloHT API implementation, once published, are made available under the license specified in the relevant repository's LICENSE file (Apache-2.0 or another license selected consistent with LEGAL_STATUS.md Section 11). Refer to the specific repository's LICENSE file for the authoritative terms.
This document is maintained alongside ARCHITECTURE.md, GOVERNANCE.md, LEGAL_STATUS.md, DONATION_POLICY.md, and NO_TOKEN_POLICY.md in the CeloHT governance and API repositories.