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.
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:
- Validate email format and password
- Check registration feature flag (early access gating)
- Create user in Keycloak via Admin API (
createUserWithCredentials) - Store user in PostgreSQL with
keycloak_user_id - Store user_information in PostgreSQL
- Sync attributes to Keycloak
- 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:
- Try Keycloak Direct Grant login
- If successful: look up user by
keycloak_user_id, check status, return tokens - If Keycloak fails: try BCrypt fallback (legacy users)
-
If BCrypt succeeds: auto-create user in Keycloak, backfill
keycloak_user_id, sync attributes, login via Keycloak - 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.
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_remainingcalculated 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
}
Health Check#
GET /health#
Check backend server health.
Response:
{
"status": "ok",
"timestamp": "2025-01-01T00:00:00Z"
}
No authentication required.
Next Steps#
- Read Statistics & Monitoring for dashboard metrics documentation
- Read Architecture Overview
- Check CLI Documentation
- Explore Development Guide