Skip to content

Admin API ​

Administrative endpoints for managing tenants, users, invitations, and API keys. These routes live under /admin/*.

Overview ​

Admin endpoints require an admin session token in Authorization: Bearer <token> (preferred) or a legacy X-Admin-Token. Most write operations require a super_admin role.

Security Warning

Admin credentials grant full system access. Store and transmit them securely.

Admin Operations

Create tenants, manage keys, users, and invitations

Authentication ​

bash
curl -X GET "https://gobananasai.com/admin/tenants" \
  -H "Authorization: Bearer <admin_session_token>"

Legacy header:

bash
curl -X GET "https://gobananasai.com/admin/tenants" \
  -H "X-Admin-Token: <legacy_admin_token>"

Tenants ​

List Tenants ​

http
GET /admin/tenants
json
{
  "data": [
    {
      "tenantId": "acme-corp",
      "tenantName": "ACME Corporation",
      "isActive": true,
      "contactEmail": "ops@acme.com",
      "monthlyQuotaMb": 10240,
      "rateLimitPerMinute": 60,
      "modelId": "gemini-flash-image",
      "allowedModels": ["gemini-flash-image", "gemini-pro-image"],
      "createdAt": "2024-01-01T00:00:00.000Z",
      "updatedAt": "2024-01-10T00:00:00.000Z"
    }
  ]
}

Get Tenant Details ​

http
GET /admin/tenants/:tenantId
json
{
  "data": {
    "tenant": {
      "tenantId": "acme-corp",
      "tenantName": "ACME Corporation",
      "isActive": true,
      "contactEmail": "ops@acme.com",
      "monthlyQuotaMb": 10240,
      "rateLimitPerMinute": 60,
      "notes": null,
      "modelId": "gemini-flash-image",
      "allowedModels": ["gemini-flash-image", "gemini-pro-image"]
    },
    "apiKeys": [
      {
        "apiKey": "sk_live_a1b2...",
        "keyName": "Production API Key",
        "isActive": true,
        "createdAt": "2024-01-01T00:00:00.000Z",
        "lastUsedAt": "2024-01-15T10:30:00.000Z",
        "usageCount": 120
      }
    ]
  }
}

Create Tenant ​

http
POST /admin/tenants

Request body (snake_case):

FieldTypeRequiredDescription
tenant_idstringYesLowercase id, e.g. new-company
tenant_namestringYesDisplay name
gemini_api_keystring*Gemini API key (legacy field; prefer provider_credentials)
provider_credentialsobject*{"gemini": "AIza...", "openai": "sk-..."}. At least one provider key is required
contact_emailstringYesOps/billing contact
monthly_quota_mbintegerNoDefault 10240
rate_limit_per_minuteintegerNoDefault 60
model_idstringNoDefault model id (defaults to gemini-flash-lite-image)
allowed_modelsstring[]NoAllowed model ids — any of gemini-flash-lite-image, gemini-flash-image, gemini-pro-image, openai-gpt-image-2, openai-gpt-image-2.5-flare, openai-gpt-image-2.5-sunburst
api_keysobject[]NoSeed keys; defaults to one live and one test
bash
curl -X POST "https://gobananasai.com/admin/tenants" \
  -H "Authorization: Bearer <admin_session_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "new-company",
    "tenant_name": "New Company LLC",
    "provider_credentials": {
      "gemini": "AIza...",
      "openai": "sk-..."
    },
    "allowed_models": ["gemini-flash-lite-image", "gemini-flash-image", "gemini-pro-image", "openai-gpt-image-2", "openai-gpt-image-2.5-flare", "openai-gpt-image-2.5-sunburst"],
    "model_id": "gemini-flash-lite-image",
    "contact_email": "ops@newco.com",
    "monthly_quota_mb": 5120,
    "rate_limit_per_minute": 30
  }'

Response:

json
{
  "data": {
    "tenant": {
      "tenantId": "new-company",
      "tenantName": "New Company LLC",
      "isActive": true,
      "contactEmail": "ops@newco.com",
      "monthlyQuotaMb": 5120,
      "rateLimitPerMinute": 30,
      "createdAt": "2024-01-15T11:00:00.000Z",
      "updatedAt": "2024-01-15T11:00:00.000Z"
    },
    "apiKeys": [
      { "apiKey": "sk_live_x1y2...", "keyName": "Production API Key", "type": "live" },
      { "apiKey": "sk_test_a1b2...", "keyName": "Test API Key", "type": "test" }
    ]
  }
}

Update Tenant ​

http
PATCH /admin/tenants/:tenantId

Body fields (snake_case) are optional: tenant_name, contact_email, is_active, monthly_quota_mb, rate_limit_per_minute, notes, model_id, allowed_models.

Response matches Get Tenant Details.

Create API Key ​

http
POST /admin/tenants/:tenantId/api-keys
bash
curl -X POST "https://gobananasai.com/admin/tenants/acme-corp/api-keys" \
  -H "Authorization: Bearer <admin_session_token>" \
  -H "Content-Type: application/json" \
  -d '{ "key_name": "Mobile App", "type": "live" }'
json
{
  "data": {
    "apiKey": "sk_live_m1n2...",
    "keyName": "Mobile App",
    "type": "live"
  }
}

Users ​

List Users ​

http
GET /admin/users
json
{
  "data": [
    {
      "userId": "user_01H...",
      "email": "admin@gobananasai.com",
      "displayName": "Admin",
      "role": "super_admin",
      "isActive": true,
      "lastLoginAt": "2024-01-10T12:00:00.000Z"
    }
  ]
}

Update User ​

http
PATCH /admin/users/:userId

Body fields (snake_case): display_name, role (admin or super_admin), is_active.

json
{
  "data": {
    "user": {
      "userId": "user_01H...",
      "role": "admin",
      "isActive": true,
      "updatedAt": "2024-01-15T12:00:00.000Z"
    }
  }
}

Unlock User Account ​

http
POST /admin/users/:userId/unlock
json
{
  "data": {
    "success": true,
    "userId": "user_01H...",
    "message": "Account unlocked successfully. Failed login attempts reset to 0."
  }
}

Invitations ​

List Invitations ​

http
GET /admin/invitations
json
{
  "data": [
    {
      "token": "inv_abcd...",
      "email": "new.admin@acme.com",
      "tenantId": "acme-corp",
      "role": "admin",
      "expiresAt": "2024-01-22T00:00:00.000Z",
      "createdAt": "2024-01-15T11:00:00.000Z"
    }
  ]
}

Create Invitation ​

http
POST /admin/invitations

Body fields (snake_case): email (required), role (admin/super_admin), tenant_id (optional), expires_in_days (default 7).

json
{
  "data": {
    "token": "inv_abcd...",
    "email": "new.admin@acme.com",
    "role": "admin",
    "tenantId": "acme-corp",
    "expiresAt": "2024-01-22T00:00:00.000Z"
  }
}

Revoke Invitation ​

http
DELETE /admin/invitations/:token
json
{ "data": { "success": true } }

Error Responses ​

Errors follow the standard format:

json
{ "error": "Human-readable message" }

Common cases:

  • 401 admin authentication required
  • 403 super_admin privileges required
  • 404 tenant/user/invitation not found

Next Steps ​

Released under the MIT License.