API
/
API overview
API overview
Two surfaces, one credential. The platform API is GraphQL; Naijamail is REST. Both take the same `nc_live_` key in an Authorization header, and what the key can reach depends on the scopes you gave it.
5 min read
The two surfaces
| Platform API | Naijamail API | |
|---|---|---|
| Style | GraphQL | REST, JSON |
| Endpoint | https://api.naijacloud.com/graphql | https://api.naijacloud.com/v1/… |
| Covers | Projects, services, deploys, databases, domains, DNS, storage | Sending and tracking email |
| Scope needed | PLATFORM_API, or a narrower one — see below | EMAIL_SEND |
They are one product with one credential. A key created in Settings → API keys works against both, and you pick which parts of each it can reach when you create it.
Authenticating
Send the key as a bearer token. Nothing else is accepted — an API key in a cookie is refused, because cookies are attached by the browser automatically and that is the property CSRF exploits.
Any request
curl https://api.naijacloud.com/graphql \
-H "Authorization: Bearer $NC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ getMyTeams { items { id name } } }"}'getMyTeams is the first call most integrations make: almost everything else
takes a teamId, and this is where you get it.
Response
{ "data": { "getMyTeams": { "items": [{ "id": "3f2b…", "name": "Acme" }] } } }Hold the key in an environment variable — NC_API_KEY is the convention — and
set it as a service variable rather than
committing it. If you deploy the calling service on Naijacloud, it is then
present on every deploy without any further setup.
Scopes
A key carries an access level and a set of resource areas. You choose the areas when you create it; the access level is inferred, because every area describes something a machine does rather than reads.
| Scope | Reaches |
|---|---|
EMAIL_SEND | The Naijamail REST API, and the mail screens' GraphQL operations |
DEPLOYS | triggerDeploy, deployment history, build and runtime logs |
DATABASES | The SQL console, saved queries, backups and restores |
PLATFORM_API | Everything else — projects, environments, services, variables, domains, DNS, storage |
Anything not covered by a narrower area needs PLATFORM_API. That is the
default rather than an exception, and it applies to parts of the API added after
your key was issued — so a narrow key does not quietly widen as the platform
grows.
The split catches people out in one place worth stating plainly: creating a
service needs PLATFORM_API, but deploying it needs DEPLOYS. A CI key that
only ships existing services wants DEPLOYS alone; a provisioning script that
creates them wants both.
Managing domains and suppression lists through the Naijamail API needs
EMAIL_SEND and PLATFORM_API. Sending is correspondence; changing a
verified sending domain is configuration, and a leaked send-only key should not
be able to point your domain somewhere else.
What a key cannot do
- Issue or revoke credentials.
createApiToken,revokeApiTokenand the Naijamail key mutations all require a signed-in human. A key can use the platform; it cannot hand out authority, so a leaked one cannot mint itself a broader replacement. - Reach the admin console. That is gated on an operator login and no API key can satisfy it.
- Exceed its owner. A key is always a subset of the person who created it. If they lose access to a workspace, so does the key.
- Reach another workspace. Keys created from the Settings card are pinned to that workspace and are refused everywhere else.
Errors
GraphQL answers 200 with an errors array — the HTTP status is about the
transport, not your query. Branch on extensions.code, never on the message
text.
An expired or revoked key
{
"errors": [
{
"message": "Invalid API token",
"extensions": { "code": "UNAUTHENTICATED" }
}
],
"data": null
}| Code | Means |
|---|---|
UNAUTHENTICATED | Missing, malformed, revoked or expired key |
FORBIDDEN | A real key without the scope or the team role for this operation |
BAD_USER_INPUT | Your variables failed validation — the message names the field |
THROTTLED | Rate limited; back off and retry |
A missing scope says which one it needs, because you are holding the key and nothing is leaked by telling you:
A key scoped only to email, calling a deploy
{
"errors": [
{
"message": "This API key does not have the DEPLOYS scope. Create a key with DEPLOYS in the dashboard, under Settings → API keys.",
"extensions": { "code": "FORBIDDEN" }
}
]
}The Naijamail API is REST and uses real status codes: 202 accepted, 401
unauthenticated, 403 scope or verification, 422 invalid body, 429 rate
limited.
Rate limits
| Surface | Default limit |
|---|---|
| Platform API | 300 requests per minute, per operation |
| Naijamail send | 3,000 requests per minute, per key |
| Creating API keys | 10 per hour, and only from a signed-in session |
A 429 is worth retrying with backoff. A 403 is not.
Request ids
Every response carries an x-request-id header. Log it. When something goes
wrong it is the one thing that lets support find your exact request rather than
guessing from a timestamp.
You can supply your own to join our logs to yours — send x-request-id with at
most 64 characters of A-Za-z0-9_.:- and it is echoed back. Anything else is
replaced with one of ours rather than rejected, so a malformed header never
fails a send.