LogoContainerPub

API Reference

Backend API endpoints and authentication

API Reference#

Complete reference for ContainerPub backend API endpoints.

Authentication#

ContainerPub uses Keycloak OIDC for authentication. Tokens are obtained via the Direct Grant flow and validated via token introspection.

For detailed authentication documentation, see [Authentication System](./authentication.md).

POST /api/auth/register#

Register a new user account. Creates user in both Keycloak and PostgreSQL.

Request:

{
  "email": "[email protected]",
  "password": "securepassword",
  "first_name": "John",
  "last_name": "Doe"
}

Response:

{
  "message": "Account created successfully"
}

Flow:

  1. Validate email format and password
  2. Check registration feature flag (early access gating)
  3. Create user in Keycloak via Admin API (createUserWithCredentials)
  4. Store user in PostgreSQL with keycloak_user_id
  5. Store user_information in PostgreSQL
  6. Sync attributes to Keycloak
  7. Return success message

Notes:

  • Password is managed by Keycloak (not stored in PostgreSQL)
  • Email must be unique
  • No tokens returned — user must login after registration

POST /api/auth/login#

Authenticate via Keycloak and receive tokens. Legacy BCrypt users are auto-migrated to Keycloak.

Request:

{
  "email": "[email protected]",
  "password": "securepassword"
}

Response:

{
  "access_token": "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "expires_in": 300,
  "token_type": "Bearer"
}

Flow:

  1. Try Keycloak Direct Grant login
  2. If successful: look up user by keycloak_user_id, check status, return tokens
  3. If Keycloak fails: try BCrypt fallback (legacy users)
  4. If BCrypt succeeds: auto-create user in Keycloak, backfill keycloak_user_id, sync attributes, login via Keycloak
  5. If both fail: return "Invalid credentials"

Status Check: Blocked or deleted users are rejected during login.

POST /api/auth/refresh#

Refresh an expired access token using Keycloak's refresh_token grant.

Request:

{
  "refresh_token": "eyJhbGc..."
}

Response:

{
  "access_token": "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "expires_in": 300,
  "token_type": "Bearer"
}

POST /api/auth/logout#

Logout and invalidate session via Keycloak.

Headers:

Authorization: Bearer <access-token>

Request:

{
  "refresh_token": "eyJhbGc..."
}

Response:

{
  "message": "Logout successful"
}

POST /api/auth/reset-password#

Initiate password reset via Keycloak native flow.

Request:

{
  "email": "[email protected]"
}

Response:

{
  "message": "If the email exists, a password reset link has been sent"
}

API Keys#

API keys provide an additional layer of security for function invocations using HMAC-SHA256 signatures.

For detailed documentation on API keys, see [API Keys & Signing](./api-keys.md).

POST /api/apikey/generate#

Generate a new API key for a function.

Headers:

Authorization: Bearer <access-token>
Content-Type: application/json

Request:

{
  "function_id": "function-uuid",
  "validity": "1d",  // Options: 1h, 1d, 1w, 1m, forever
  "name": "Optional key name"
}

Response:

{
  "message": "API key generated successfully",
  "warning": "Store the private_key securely - it will not be shown again!",
  "api_key": {
    "uuid": "key-uuid",
    "public_key": "base64-public-key",
    "private_key": "base64-private-key",
    "validity": "1d",
    "expires_at": "2025-12-16T02:00:00Z",
    "created_at": "2025-12-15T02:00:00Z"
  }
}

GET /api/apikey/:function_id#

Get API key info for a function.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "has_api_key": true,
  "api_key": {
    "uuid": "key-uuid",
    "public_key": "base64-public-key",
    "validity": "1d",
    "is_active": true,
    "expires_at": "2025-12-16T02:00:00Z"
  }
}

DELETE /api/apikey/:api_key_uuid/revoke#

Revoke an API key (deactivate but keep in history).

Headers:

Authorization: Bearer <access-token>

Response:

{
  "message": "API key revoked successfully"
}

What it does:

  • Marks the API key as inactive
  • Records the revocation timestamp
  • Key remains in database for audit history
  • Cannot be reactivated

DELETE /api/apikey/:api_key_uuid#

Delete an API key (remove from database).

Headers:

Authorization: Bearer <access-token>

Response:

{
  "message": "API key revoked successfully"
}

What it does:

  • Permanently removes the API key from the database
  • No audit trail remains
  • Cannot be recovered

GET /api/apikey/:function_id/list#

List all API keys for a function.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "api_keys": [
    {
      "uuid": "key-uuid",
      "validity": "1d",
      "is_active": true,
      "expires_at": "2025-12-16T02:00:00Z"
    }
  ]
}

PUT /api/apikey/:api_key_uuid/roll#

Extend an API key's expiration by its validity period.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "message": "API key updated successfully"
}

What it does:

  • Extends the expiration date by the key's validity period
  • For example, if validity is 1d, it adds 1 day to the current expiration
  • Useful for extending active keys without regenerating them
  • Does not change the key UUID or secret

PUT /api/apikey/:api_key_uuid/update#

Update an API key's validity period.

Headers:

Authorization: Bearer <access-token>
Content-Type: application/json

Request:

{
  "validity": "1w",  // New validity: 1h, 1d, 1w, 1m, forever
  "name": "Updated key name"  // Optional
}

Response:

{
  "message": "API key updated successfully"
}

PUT /api/apikey/:api_key_uuid/enable#

Re-enable a revoked API key.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "message": "API key enabled successfully"
}

Notes:

  • Only works on revoked keys (is_active = false)
  • Sets is_active to true
  • Does not change expiration date

Token Security#

Tokens are issued and managed by Keycloak. The platform backend validates tokens via Keycloak's introspection endpoint on every request. A legacy JWT fallback exists during the migration period.

For details, see Authentication System.

Functions API#

POST /api/functions/init#

Initialize a new function (creates UUID and database record).

Headers:

Authorization: Bearer <access-token>
Content-Type: application/json

Request:

{
  "name": "my_function",
  "skip_signing": false  // Optional, default: false
}

Response (New Function):

{
  "message": "Function initialized successfully",
  "id": "function-uuid",
  "name": "my_function",
  "status": "init",
  "skip_signing": false,
  "created_at": "2025-01-01T00:00:00Z"
}

Response (Existing Function):

{
  "message": "Function already exists",
  "id": "function-uuid",
  "name": "my_function",
  "status": "active",
  "skip_signing": false,
  "deployment_version": 3,
  "created_at": "2025-01-01T00:00:00Z",
  "already_exists": true
}

Notes:

  • Must be called before deployment
  • Creates function record with status init
  • Returns existing function if name already exists for user
  • Generates unique UUID for the function

POST /api/functions/deploy#

Deploy a new function or update existing one.

Headers:

Authorization: Bearer <access-token>
Content-Type: multipart/form-data

Form Data:

  • function_id - Function UUID (from init endpoint)
  • archive - Function archive (tar.gz)
  • env - Environment variables (JSON, optional)

Response:

{
  "id": "function-id",
  "name": "my-function",
  "status": "deployed",
  "url": "https://api.containerpub.dev/functions/function-id"
}

GET /api/functions#

List all deployed functions for authenticated user.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • limit - Number of results (default: 10)
  • offset - Pagination offset (default: 0)

Response:

{
  "functions": [
    {
      "id": "function-id",
      "name": "my-function",
      "status": "active",
      "created_at": "2025-01-01T00:00:00Z"
    }
  ],
  "total": 1
}

GET /api/functions/:id#

Get function details.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "id": "function-id",
  "name": "my-function",
  "status": "active",
  "memory": 512,
  "timeout": 30,
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-01-01T00:00:00Z"
}

DELETE /api/functions/:id#

Delete a function.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "message": "Function deleted successfully"
}

Function Execution#

POST /api/functions/:id/invoke#

Invoke a deployed function.

Headers:

Authorization: Bearer <access-token>
Content-Type: application/json

Request:

{
  "body": {
    "key": "value"
  }
}

Response:

{
  "execution_id": "exec-id",
  "status": "success",
  "result": {
    "output": "result"
  },
  "duration_ms": 150
}

GET /api/functions/:id/executions#

Get execution history for a function with pagination.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • page - Page number (default: 1)
  • per_page - Results per page (default: 20, max: 100)

Response:

{
  "executions": [
    {
      "uuid": "exec-uuid",
      "status": "success",
      "started_at": "2025-01-01T00:00:00Z",
      "completed_at": "2025-01-01T00:00:05Z",
      "duration_ms": 150
    }
  ],
  "page": 1,
  "per_page": 20,
  "total": 45,
  "has_next": true
}

GET /api/functions/:id/executions/:executionUuid#

Get detailed information about a specific execution.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "execution": {
    "uuid": "exec-uuid",
    "function_uuid": "function-uuid",
    "status": "success",
    "started_at": "2025-01-01T00:00:00Z",
    "completed_at": "2025-01-01T00:00:05Z",
    "duration_ms": 150,
    "invocation": {
      "uuid": "invocation-uuid",
      "timestamp": "2025-01-01T00:00:00Z",
      "success": true,
      "duration_ms": 150,
      "error_message": null
    },
    "logs": [
      {
        "timestamp": "2025-01-01T00:00:01Z",
        "level": "info",
        "message": "Function started"
      }
    ]
  }
}

Versioning & Rollback#

GET /api/functions/:id/deployments#

Get deployment history for a function with pagination.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • page - Page number (default: 1)
  • per_page - Results per page (default: 20, max: 100)

Response:

{
  "function_uuid": "function-uuid",
  "function_name": "my-function",
  "function_status": "active",
  "page": 1,
  "per_page": 20,
  "count": 5,
  "total_pages": 1,
  "has_next": false,
  "deployments": [
    {
      "uuid": "deployment-uuid",
      "version": 3,
      "image_tag": "registry/my-function:v3",
      "s3_key": "functions/uuid/v3.tar.gz",
      "status": "active",
      "is_active": true,
      "created_at": "2025-01-03T00:00:00Z",
      "deployed_at": "2025-01-03T00:01:00Z"
    },
    {
      "uuid": "deployment-uuid-2",
      "version": 2,
      "image_tag": "registry/my-function:v2",
      "s3_key": "functions/uuid/v2.tar.gz",
      "status": "inactive",
      "is_active": false,
      "created_at": "2025-01-02T00:00:00Z",
      "deployed_at": "2025-01-02T00:01:00Z"
    }
  ]
}

POST /api/functions/:id/rollback#

Rollback function to a previous deployment version.

Headers:

Authorization: Bearer <access-token>
Content-Type: application/json

Request:

{
  "version": 2  // Version number to rollback to
}

Response:

{
  "message": "Function rolled back successfully",
  "function": {
    "uuid": "function-uuid",
    "name": "my-function",
    "status": "active",
    "active_version": 2
  }
}

Notes:

  • Rollback restores the specified version as the active deployment
  • Previous active deployment is marked as inactive
  • Function container is restarted with the rolled-back version

Deletion Management#

POST /api/functions/:uuid/cancel-deletion#

Cancel a pending deletion for a function.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "success": true,
  "message": "Deletion cancelled successfully",
  "function": {
    "uuid": "function-uuid",
    "name": "my-function",
    "status": "active"
  }
}

Notes:

  • Cancels all pending image deletions for the function
  • Restores function status to active
  • Can only cancel deletions with status pending

GET /api/functions/pending-deletions#

Get all pending deletions for the authenticated user.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "pending_deletions": [
    {
      "id": "pending-deletion-uuid",
      "function_uuid": "function-uuid",
      "function_name": "my-function",
      "function_status": "pending_deletion",
      "image_tag": "registry/my-function:v1",
      "reason": "stale_function",
      "deletion_date": "2025-02-01T00:00:00Z",
      "days_remaining": 7,
      "scheduled_at": "2025-01-25T10:30:00Z"
    }
  ],
  "count": 1
}

Notes:

  • Returns only deletions with status pending
  • Ordered by deletion date (earliest first)
  • days_remaining calculated from current date

GET /api/functions/:uuid/deletion-status#

Get deletion status for a specific function.

Headers:

Authorization: Bearer <access-token>

Response:

{
  "function_uuid": "function-uuid",
  "function_name": "my-function",
  "has_pending_deletion": true,
  "deletion_info": {
    "id": "pending-deletion-uuid",
    "image_tag": "registry/my-function:v1",
    "reason": "stale_function",
    "deletion_date": "2025-02-01T00:00:00Z",
    "days_remaining": 7,
    "scheduled_at": "2025-01-25T10:30:00Z"
  }
}

Logs API#

GET /api/functions/:id/logs#

Get function execution logs.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • limit - Number of lines (default: 100)
  • since - Timestamp filter (ISO 8601)

Response:

{
  "logs": [
    {
      "timestamp": "2025-01-01T00:00:00Z",
      "level": "info",
      "message": "Function started"
    }
  ]
}

Error Responses#

400 Bad Request#

{
  "error": "Invalid request",
  "details": "Missing required field: name"
}

401 Unauthorized#

{
  "error": "Unauthorized",
  "details": "Invalid or expired token"
}

Common Causes:

  • Missing Authorization header
  • Invalid access token
  • Expired access token (use refresh token to get new one)

403 Forbidden#

{
  "error": "Forbidden",
  "details": "Access denied"
}

404 Not Found#

{
  "error": "Not found",
  "details": "Function not found"
}

500 Internal Server Error#

{
  "error": "Internal server error",
  "details": "An unexpected error occurred"
}

Rate Limiting#

  • Requests per minute: 60
  • Requests per hour: 1000
  • Concurrent executions: 10 per function

Statistics API#

GET /api/stats/overview#

Get aggregated statistics for all user's functions.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • period - Time period: 1h, 24h, 7d, 30d (default: 24h)

Response:

{
  "total_functions": 5,
  "invocations_count": 1250,
  "success_count": 1245,
  "error_count": 5,
  "average_latency_ms": 120,
  "period": "24h"
}

GET /api/stats/overview/hourly#

Get hourly chart data for all user's functions.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • hours - Number of hours (default: 24, max: 168)

Response:

{
  "data": [
    {
      "hour": "2024-01-15T10:00:00Z",
      "total_requests": 150,
      "success_count": 148,
      "error_count": 2,
      "average_latency_ms": 120
    }
  ],
  "hours": 24
}

GET /api/stats/overview/daily#

Get daily chart data for all user's functions.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • days - Number of days (default: 30, max: 90)

Response:

{
  "data": [
    {
      "day": "2024-01-15T00:00:00Z",
      "total_requests": 1500,
      "success_count": 1495,
      "error_count": 5,
      "average_latency_ms": 115
    }
  ],
  "days": 30
}

GET /api/functions/:uuid/stats#

Get statistics for a specific function.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • period - Time period: 1h, 24h, 7d, 30d (default: 24h)

Response:

{
  "invocations_count": 250,
  "success_count": 248,
  "error_count": 2,
  "average_latency_ms": 125,
  "period": "24h"
}

GET /api/functions/:uuid/stats/hourly#

Get hourly chart data for a specific function.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • hours - Number of hours (default: 24, max: 168)

Response:

{
  "data": [
    {
      "hour": "2024-01-15T10:00:00Z",
      "total_requests": 25,
      "success_count": 24,
      "error_count": 1,
      "average_latency_ms": 125
    }
  ],
  "hours": 24
}

GET /api/functions/:uuid/stats/daily#

Get daily chart data for a specific function.

Headers:

Authorization: Bearer <access-token>

Query Parameters:

  • days - Number of days (default: 30, max: 90)

Response:

{
  "data": [
    {
      "day": "2024-01-15T00:00:00Z",
      "total_requests": 250,
      "success_count": 248,
      "error_count": 2,
      "average_latency_ms": 125
    }
  ],
  "days": 30
}
For detailed documentation on statistics and monitoring, see [Statistics & Monitoring](./statistics.md).

Health Check#

GET /health#

Check backend server health.

Response:

{
  "status": "ok",
  "timestamp": "2025-01-01T00:00:00Z"
}

No authentication required.

Next Steps#