Skip to main content

Authentication

Every request to a /v1 endpoint is authenticated with an API key sent as a Bearer token in the Authorization header:

curl -s "https://api.chatbots.ecourtdate.com/v1/models" \
-H "Authorization: Bearer $API_KEY"

There is no unauthenticated /v1 operation. Only GET /health is open; it returns {"status": "ok"} and takes no key. A request without a valid key is rejected with 401 invalid_api_key; a valid key that lacks the scope an operation needs is rejected with 403 insufficient_scope.

Getting a key

Access to the eCourtDate Chatbot API requires a paid subscription. API keys are issued and activated for your account by eCourtDate; there is no self-serve key page. Contact eCourtDate to request a key, to add or remove a scope, or to have a key revoked.

A key is the prefix ecd_sk_ followed by 59 characters, 66 characters in total. The first 16 characters after the prefix identify the key; the rest is the secret. When you talk to support about a key, quote the key id (ecd_sk_ plus those 16 characters), never the full value.

The OpenAI SDKs send the key for you; pass it as api_key (Python) or apiKey (Node) together with the base URL:

from openai import OpenAI

client = OpenAI(
api_key="ecd_sk_...",
base_url="https://api.chatbots.ecourtdate.com/v1",
)
import OpenAI from "openai";

const client = new OpenAI({
apiKey: process.env.API_KEY,
baseURL: "https://api.chatbots.ecourtdate.com/v1",
});

Send the header exactly as Authorization: Bearer ecd_sk_...: one space between the scheme and the key. The scheme word is matched case-insensitively, but other spellings and whitespace variants are not part of the contract.

Scopes

Each key carries one or both scopes. The scope gates which operations the key may call; within a scope, every resource is limited to your own account.

ScopeGrants
chatChat completions, models, embeddings, and conversations
ingestUploading files, crawling websites, documents, and job status

The full matrix:

OperationScope
POST /v1/chat/completionschat
GET /v1/models, GET /v1/models/{modelId}chat
POST /v1/embeddingschat
POST /v1/conversations, GET /v1/conversations/{conversationId}, DELETE /v1/conversations/{conversationId}, POST /v1/conversations/{conversationId}/messageschat
POST /v1/ingest/files, GET /v1/ingest/jobs/{jobId}ingest
POST /v1/ingest/crawl, GET /v1/ingest/crawl/{crawlJobId}ingest
GET /v1/documents, GET /v1/documents/{documentId}, DELETE /v1/documents/{documentId}ingest

The API reference shows the required scope on every operation. A practical split: give the service that powers your public chat widget a chat-only key, and give the back-office process that uploads documents an ingest-only key. Neither can do the other's job, and each can be rotated or revoked independently.

401 versus 403

The two statuses mean different things and call for different fixes.

401 invalid_api_key: the request did not authenticate. The body is identical for every cause (missing header, wrong scheme, malformed key, unknown key, wrong secret, expired key, revoked key, or a suspended account), so the response never reveals which part was wrong. The response also carries WWW-Authenticate: Bearer.

HTTP/1.1 401 Unauthorized
Content-Type: application/json
WWW-Authenticate: Bearer
X-Request-ID: 1f0a7b2c9d8e4f6a8b1c2d3e4f5a6b7c
{
"error": {
"message": "Incorrect API key provided.",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key"
}
}

Fix: check that the header is present and well-formed and that the key is the one eCourtDate activated for your account. If the key was valid until recently, it may have expired or been revoked; see Key lifecycle.

403 insufficient_scope: the key authenticated, but it does not carry the scope the operation requires. The message names the missing scope.

{
"error": {
"message": "This API key does not have the 'ingest' scope.",
"type": "invalid_request_error",
"param": null,
"code": "insufficient_scope"
}
}

Fix: use a key that carries the scope, or ask eCourtDate to add the scope to this key. Retrying the same request with the same key will not succeed.

Authentication and scope are checked before the rate limiter and before the request body is validated, so:

  • A request with no key and a body that fails validation returns 401, not 400. The one body check that runs earlier is JSON syntax: a body that is not valid JSON is rejected with 400 (Invalid JSON in request body.) even without a key.
  • Requests rejected with 401 or 403 do not count against your rate limit.
  • The other checks that run earlier are a malformed Content-Length header (400), the request body size cap, which returns 413 request_too_large even without a key, and routing: an unknown path (404) or an unsupported method (405) is reported before the key is checked (evaluation order).

Key lifecycle

  • Activation. A key works as soon as eCourtDate activates it for your account.
  • Expiry. A key may carry an expiry date. Until that date it authenticates normally; after it, every request returns 401 invalid_api_key. eCourtDate tells you the expiry date when the key is issued.
  • Revocation. eCourtDate revokes a key on your request or when a compromise is suspected. A revoked key returns 401 invalid_api_key. Successful verifications are cached briefly, so allow up to a minute for a revocation to take effect everywhere.
  • Account status. If the subscription is suspended, every key on the account returns 401 invalid_api_key until it is reinstated.

Nothing about expiry or revocation is reported in the error body; the 401 is the same in every case. Treat an unexpected 401 from a key that was working as a signal to check with eCourtDate rather than to retry.

Rotation

Rotate keys on a schedule and immediately on suspected exposure. Because keys are issued by eCourtDate, plan the rotation so there is no gap:

  1. Ask eCourtDate for a replacement key with the same scopes.
  2. Deploy the new key to every integration that used the old one.
  3. Confirm the integrations authenticate with the new key (a GET /v1/models call is a cheap check for a chat key; GET /v1/documents?limit=1 for an ingest key).
  4. Ask eCourtDate to revoke the old key.

Both keys authenticate during the overlap, so the order above never produces a 401 in production. Keep one key per integration: a leak then affects a single system, and the key id in your logs and in support conversations points at exactly one deployment.

Server-side only

API keys are server-side secrets. Never embed one in a web page, a mobile app, or any client you do not control: anyone who can read the client can read the key and spend your quota. Browser-direct calls are not a supported scenario, and cross-origin requests are accepted only from eCourtDate-owned origins. Put your own service between the browser and the API: the browser calls your backend, your backend holds the key and calls https://api.chatbots.ecourtdate.com/v1.

Other handling rules:

  • Store keys in a secrets manager or environment variables, never in source control.
  • Do not log the Authorization header. Log the X-Request-ID instead; it identifies the request to support without exposing the key.
  • Scope each key as narrowly as the integration needs (Scopes).

See Security for data handling beyond keys.

Errors

StatusCodeWhen
401invalid_api_keyNo key, malformed header, unknown, expired, or revoked key, suspended account
403insufficient_scopeThe key lacks the scope the operation requires
413request_too_largeThe body exceeds the cap; checked before authentication
429rate_limit_exceeded, insufficient_quotaChecked after authentication and scope