Skip to content
Menu
POST /api/v1/developers

Create an API key

Create an API key.

Registers a developer and issues a key. It is the one unauthenticated write endpoint — you need a key to get a key — so it is metered per IP address instead of per key.

The plaintext key is returned exactly once. Only a SHA-256 hash and a short display prefix are stored, so it cannot be retrieved afterwards; losing it means issuing another.

The route does not send a plan, so every developer registered here is created on the free plan. Registration is idempotent on email: an existing developer receives an additional key rather than a duplicate account.

Because this endpoint is not metered by key, it has no plan_limit row and no X-RateLimit-* headers. Its limit is the per-IP throttle described on the Rate limits page.

Path
/api/v1/developers
Authentication
None. This endpoint takes no key.
Rate limit
Not counted against a key: throttled per IP address.
Operation id
createDeveloper

Parameters

Parameters as the OpenAPI document declares them. Nothing is required unless the table says so.
NameInTypeRequiredDescription
namebodystringRequiredRequired. Up to 200 characters.
emailbodystring (email)RequiredRequired. Up to 200 characters, lower-cased before storage, and checked against a permissive address shape.
organizationbodystringOptionalOptional. Truncated to 200 characters.
useCasebodystringOptionalOptional. Truncated to 500 characters.
keyNamebodystringOptionalNot in the OpenAPI document. The route reads it and stores it as the key's display name; it defaults to default.

Example request

The curl works against the live API once OZITUMA_API_KEY holds your key.

curl -X POST "https://ozituma.com/api/v1/developers" \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada","email":"[email protected]","useCase":"language learning app"}'

The same request, raw

POST /api/v1/developers HTTP/1.1
Host: ozituma.com
Content-Type: application/json

{"name":"Ada","email":"[email protected]","useCase":"language learning app"}

Example response

{
  "developer": {
    "id": "6f9c1e2a-…",
    "name": "Ada",
    "email": "[email protected]",
    "plan": "free"
  },
  "apiKey": "ozt_live_…",
  "keyPrefix": "ozt_live_…",
  "warning": "Store this key now. It is hashed on our side and cannot be shown again.",
  "usage": "Send it as the X-API-Key header. See /docs for endpoints."
}

The 201 body the route returns, with the account id and the key redacted. warning and usage are the route's own strings. The document types this response as a plain object without listing the fields.

Errors

Responses the OpenAPI document lists

StatusWhat the document says
201Key created. The plaintext key is returned once and never again.
400Invalid body
429Daily quota exceeded for your plan

Codes this route can return

StatusCodeWhen
400invalid_parameterA query or body parameter is missing, malformed, or outside its range. The message names the parameter.
429rate_limitedPOST /api/v1/developers only: more than 5 key requests from one IP address in a 15-minute window. The response carries Retry-After: 900.
500internal_errorAn unexpected server error. The message is generic on purpose; a stack trace or a SQL error is never returned to a caller.

The body of every failure is the same. Errors explained →

Where the document and the implementation differ

Read from the route source and the OpenAPI document together. Where the two disagree, this is what each one says.

  • The document declares this operation's 429 as the shared QuotaExceeded response ("Daily quota exceeded for your plan"). This route uses no key quota: its 429 is rate_limited, from the per-IP throttle, and carries Retry-After: 900.
  • The route can also return 500 (internal_error), which the document does not list.
  • The route accepts a keyName body field that the document does not list.
  • The document marks the request body required and name and email required. The route enforces exactly that: either field missing or malformed is a 400.