Important
All API requests must include an Authorization header in the following format: Authorization: Bearer <API_TOKEN>
All endpoints return JSON responses with appropriate HTTP status codes
Endpoint: /api/crons
Method: GET
Description: Returns the current settings for all cron jobs.
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/cronsResponse Example:
[
{
"name": "collect",
"schedule": "0 13 * * 6",
"is_active": true,
"updated_at": "2024-03-15T10:00:00Z"
},
{
"name": "message",
"schedule": "12 10 * * *",
"is_active": true,
"updated_at": "2024-03-15T10:00:00Z"
}
]Endpoint: /api/crons/{name}/schedule
Method: PUT
Description: Update the schedule for a specific cron job. The name can be either collect or message.
Curl Example:
curl -X PUT \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"schedule": "0 15 * * 6"}' \
http://localhost:8080/api/crons/collect/scheduleRequest Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Cron job name (collect or message) |
schedule |
string | Yes | Cron schedule expression (e.g.,0 15 * * 6) |
Request Example:
{
"schedule": "0 15 * * 6"
}Response Example:
{
"status": "success",
"message": "Schedule updated successfully"
}Endpoint: /api/crons/{name}/status
Method: PUT
Description: Enable or disable a specific cron job. The name can be either collect or message.
Curl Example:
curl -X PUT \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"is_active": true}' \
http://localhost:8080/api/crons/collect/statusRequest Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Cron job name (collect or message) |
is_active |
boolean | Yes | Enable (true) or disable (false) the job |
Request Example:
{
"is_active": false
}Response Example:
{
"status": "success",
"message": "Status updated successfully"
}Endpoint: /api/collect-settings
Method: GET
Description: Returns the current settings for repository collection.
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/collect-settingsResponse Example:
{
"max_repos": 5,
"resource": "github",
"since": "daily",
"spoken_language_code": "en",
"period": "past_24_hours",
"language": "All"
}Note
All fields are stored in the database, but only relevant fields are used based on the resource value:
- GitHub: uses
since,spoken_language_code - OssInsight: uses
period,language
Endpoint: /api/collect-settings
Method: PUT
Description: Update the repository collection settings.
Curl Example:
curl -X PUT \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"max_repos": 10,
"resource": "github",
"since": "weekly",
"spoken_language_code": "uk",
"period": "past_24_hours",
"language": "All"
}' \
http://localhost:8080/api/collect-settingsRequest Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
max_repos |
integer | No | Maximum number of repositories to collect |
resource |
string | No | Data source:github (default) or ossinsight |
since |
string | No | For GitHub: Time period (daily, weekly, monthly) |
spoken_language_code |
string | No | For GitHub: Spoken language filter (e.g., en, uk, es) |
period |
string | No | For OssInsight: Time period (past_24_hours, past_week, past_month, past_3_months) |
language |
string | No | For OssInsight: Programming language filter (e.g., Python, All) |
Request Example:
{
"max_repos": 10,
"resource": "github",
"since": "weekly",
"spoken_language_code": "uk",
"period": "past_24_hours",
"language": "All"
}Response Example:
{
"status": "success",
"message": "Collect settings updated successfully"
}Endpoint: /api/prompt-settings
Method: GET
Description: Returns the current AI prompt settings used for content generation.
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/prompt-settingsResponse Example:
{
"use_direct_url": true,
"llm_provider": "openrouter",
"temperature": 0.1,
"model": "openai/gpt-4o-mini-search-preview",
"content": "You are a helpful AI assistant that generates engaging content about software repositories.",
"updated_at": "2024-03-15T10:00:00Z"
}Endpoint: /api/prompt-settings
Method: PUT
Description: Update the AI prompt settings for content generation.
Curl Example:
curl -X PUT \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"use_direct_url": false,
"llm_provider": "anthropic",
"temperature": 0.8,
"model": "anthropic/claude-3-sonnet",
"content": "You are an expert technical writer specializing in open-source projects."
}' \
http://localhost:8080/api/prompt-settingsRequest Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
use_direct_url |
boolean | No | Whether to use direct URL for LLM API calls |
llm_provider |
string | No | LLM provider name (e.g.,openai, mistral_agent, mistral_api, openrouter) |
temperature |
float | No | Controls randomness in AI responses (0.0-2.0) |
model |
string | No | The AI model to use for content generation |
content |
string | No | The prompt content/template for AI generation |
Request Example:
{
"use_direct_url": false,
"llm_provider": "openrouter",
"temperature": 0.1,
"model": "openai/gpt-4o-mini",
"content": "You are an expert technical writer specializing in open-source projects."
}Response Example:
{
"status": "success",
"message": "Prompt settings updated successfully"
}Endpoint: /api/cron-history
Method: GET
Description: Retrieve the history of cron job executions with pagination, sorting, and filtering.
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?name=collect&page=1&limit=10"Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | No | Filter by cron job name (collect or message) |
page |
integer | No | Page number (default: 1) |
limit |
integer | No | Number of records per page (default: 20) |
sort |
string | No | Sort order by execution date (asc or desc, default: desc) |
status |
integer | No | Filter by execution status:0 (Failure), 1 (Success), 2 (Partial) |
start_date |
string | No | Filter records from this date onwards (format:YYYY-MM-DD or RFC3339) |
end_date |
string | No | Filter records up to this date (format:YYYY-MM-DD or RFC3339) |
Response Structure:
The API returns a paginated response with the following structure.
Note that the status field uses integer status codes:
0: Failure1: Success2: Partial Success
Structure:
data: Array of cron history recordsdetails: Present on message runs recorded after this field was introduced. Holds the item that was published and where it landed:url,sent,failed, andmanual(true for runs triggered through/api/message/retry). Absent for older records and for collect runs.pagination: Pagination metadata object containing:total_count: Total number of records matching the filterscurrent_page: Current page numbertotal_pages: Total number of pages availablehas_next: Boolean indicating if there's a next pagehas_previous: Boolean indicating if there's a previous page
Response Example:
{
"data": [
{
"name": "collect",
"timestamp": "2024-03-15T10:00:00Z",
"status": 1,
"output": "Successfully collected 5 repositories"
},
{
"name": "message",
"timestamp": "2024-03-15T10:05:00Z",
"status": 0,
"output": "Network error"
},
{
"name": "message",
"timestamp": "2024-03-15T10:10:00Z",
"status": 2,
"output": "Message sent to: telegram. Failed: bluesky",
"details": {
"url": "https://github.com/resemble-ai/chatterbox",
"sent": ["telegram"],
"failed": ["bluesky"]
}
}
],
"pagination": {
"total_count": 25,
"current_page": 1,
"total_pages": 2,
"has_next": true,
"has_previous": false
}
}Usage Examples:
- Get all history (default: newest first, 20 records per page):
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/cron-history- Get history for specific job with custom pagination:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?name=collect&page=1&limit=10"- Get only failed executions sorted by oldest first:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?status=0&sort=asc&limit=5"- Get message job history with pagination and newest first sorting:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?name=message&page=2&limit=15&sort=desc"- Get second page of all executions with 10 records per page:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?page=2&limit=10"- Get history for a specific date range (from March 1st to March 15th, 2024):
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?start_date=2024-03-01&end_date=2024-03-15"- Get failed executions from the last week:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?status=0&start_date=2024-03-08"- Get collect job history for a specific date with precise timestamps:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?name=collect&start_date=2024-03-15T00:00:00Z&end_date=2024-03-15T23:59:59Z"- Get recent executions from the last 3 days, sorted oldest first:
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:8080/api/cron-history?start_date=2024-03-12&sort=asc"Date Range Filtering Notes:
- Supported date formats:
- Date only:
YYYY-MM-DD(e.g.,2024-03-15) - RFC3339 with timezone:
YYYY-MM-DDTHH:MM:SSZ(e.g.,2024-03-15T10:30:00Z)
- Date only:
- Date validation:
- Invalid date formats will return a
400 Bad Requesterror - If
start_dateis afterend_date, the API will return a400 Bad Requesterror
- Invalid date formats will return a
- Date range behavior:
start_dateis inclusive (records from this date onwards)end_dateis inclusive (records up to the end of this date)- When using date-only format,
end_dateincludes the entire day (until 23:59:59.999...)
- Timezone handling:
- All timestamps are stored and compared in UTC
- When using date-only format, the date is interpreted as the start of the day in UTC
Status Codes:
- 200: Success
- 400: Bad Request - Invalid parameters or date validation errors
- 401: Unauthorized - Invalid or missing Bearer token
- 500: Internal Server Error - Database or server error
Endpoint: /api/message/retry
Method: POST
Description: Re-send an already published repository to the integrations that did not receive it.
A message run marks the repository as posted as soon as any integration succeeds, which drops the item out of the publication queue. The connectors that failed can therefore never recover it on the next run β this endpoint is the way to finish such a partial publication by hand.
The repository text is fetched per integration in that integration's configured text_language, and one image is generated for the whole retry when any integration has socialify_image enabled. No Pushover notification is sent: a manual retry is already being watched by whoever triggered it.
Retries are serialised against each other, against /api/message/publish and against the message cron β a double-clicked button cannot publish twice, and a cron run cannot mark an item it never sent. Unlike publish-now, a retry waits for whatever holds that lock instead of refusing: it is a repair action, and refusing it would leave the connectors that failed unrepaired. The wait is unbounded and there is no request timeout, so a retry issued during a cron run can hold its connection for the length of that run (minutes, in the worst case described under /api/message/publish); repeated clicks queue up behind it rather than failing fast.
An item that is still unposted is marked as posted only when every requested integration succeeded; marking it after a partial retry would drop it out of the queue again, which is the failure this endpoint repairs.
Curl Example:
curl -X POST \
'http://localhost:8080/api/message/retry' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"apis": ["threads"],
"url": "https://github.com/resemble-ai/chatterbox"
}'Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
apis |
string[] | Yes | Names of the integrations to send to, as configured in/api/api-configs. Blanks and duplicates are ignored. |
url |
string | No | Repository to publish. When omitted the most recently published repository is used, which is only a guess at what a partial run consumed: a run that failed for every integration never marked its item as posted, so the guess resolves to the previous one. Callers that know the item β the dashboard reads it from the run details β should always pass it. |
Response Structure:
url: The repository that was publishedstatus:0(nothing sent),1(all sent),2(partially sent) β the same codes as cron historymessage: The text recorded in cron historysucceeded/failed: Integration names per outcomeoutcomes: Per-integration detail, with anerrorstring for every failureposted: Whether the item was marked as published and left the publication queueposted_error: Present only when that marking failed β the item went out but stayed in the queue, so the scheduled run will publish it again
Response Example:
{
"url": "https://github.com/resemble-ai/chatterbox",
"status": 1,
"message": "Manual retry: https://github.com/resemble-ai/chatterbox sent to: threads",
"succeeded": ["threads"],
"failed": null,
"outcomes": [{ "api_name": "threads", "success": true }]
}Every retry is recorded in cron history under the message name with details.manual = true, so /api/cron-history shows it alongside scheduled runs.
Status Codes:
- 200: The retry ran. Individual integration failures are reported in
outcomes, not in the status code - 400: Bad Request - Invalid body or an empty
apislist - 401: Unauthorized - Invalid or missing Bearer token
- 500: Internal Server Error - API configurations not loaded, or the repository could not be resolved
Endpoint: /api/message/publish
Method: POST
Description: Publish one repository to every enabled integration immediately, instead of waiting for its turn in the publication queue.
It exists because a post that is lost after publication β a bad record deleted from the queue once it was already sent β cannot be recovered by promoting anything: the item is gone from the queue. Promoting a repository (content-alchemist's /promote-repository/) only moves it to the head of the queue; this endpoint publishes it now.
There is no apis parameter: the run targets every integration whose api_configs row has enabled = true, resolved server-side at request time. A dashboard's cached configuration must not decide what actually gets published.
The repository text is fetched per integration in that integration's configured text_language, and one image is generated for the whole run when any integration has socialify_image enabled. No Pushover notification is sent β whoever triggered the run is watching it.
Unlike the message cron this does not revalidate the repository URL and delete dead ones: the cron picks blindly from the queue, while this publishes the row a human chose.
Marking as posted: the item is marked as published as soon as any integration accepts it, matching the message cron (and unlike /api/message/retry, which requires every requested integration to succeed). The run is recorded in cron history as a manual one, so the integrations that failed are finished off from there with the retry endpoint.
Concurrency: serialised against the message cron and the retry endpoint. Rather than queueing behind a cron run that can take minutes, it refuses with 409. A repository that is already published is refused with 409 as well, before any integration is contacted β a stale dashboard row must not publish the same post twice.
Duration: the request is synchronous and can take minutes β image generation retries for up to ~63 s, the Threads connector alone is configured with a 90 s timeout, and every integration adds its own repository lookup. Any reverse proxy in front of content-maestro needs a matching read timeout, or the browser gets a 504 while the publication keeps running.
Curl Example:
curl -X POST \
'http://localhost:8080/api/message/publish' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://github.com/resemble-ai/chatterbox"
}'Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Repository to publish. There is no fallback: "publish something now" is never a safe guess. |
Response Structure: identical to /api/message/retry β url, status, message, succeeded, failed, outcomes, posted, posted_error.
Response Example:
{
"url": "https://github.com/resemble-ai/chatterbox",
"status": 2,
"message": "Manual publish: https://github.com/resemble-ai/chatterbox sent to: telegram. Failed: threads. Errors: threads: API request failed with status 500",
"succeeded": ["telegram"],
"failed": ["threads"],
"outcomes": [
{ "api_name": "telegram", "success": true },
{ "api_name": "threads", "success": false, "error": "API request failed with status 500" }
],
"posted": true
}Every run is recorded in cron history under the message name with details.manual = true, so /api/cron-history shows it alongside scheduled runs β and its details.failed list is what the retry endpoint works from.
Status Codes:
- 200: The publication ran. Individual integration failures are reported in
outcomes, not in the status code - 400: Bad Request - Invalid body or a missing
url - 401: Unauthorized - Invalid or missing Bearer token
- 409: Conflict - Another publication is already running, no integration is enabled, or the repository is already published
- 500: Internal Server Error - API configurations not loaded, or the repository could not be resolved
Endpoint: /api/api-configs
Method: GET
Description: Retrieve all API configurations for external integrations (Twitter, Telegram, Bluesky, etc.).
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/api-configsResponse Example:
[
{
"id": 1,
"name": "twitter",
"url": "{env.TWITTER_URL}/x/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "TWITTER_API_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "en",
"socialify_image": false,
"default_json_body": "",
"updated_at": "2024-03-15T10:00:00Z"
},
{
"id": 2,
"name": "telegram",
"url": "{env.TELEGRAM_SERVER_URL}/telegram/send-message",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "TELEGRAM_SERVER_TOKEN",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "uk",
"socialify_image": true,
"default_json_body": "",
"updated_at": "2024-03-15T10:00:00Z"
}
]Endpoint: /api/api-configs/{name}
Method: GET
Description: Retrieve a specific API configuration by name.
Curl Example:
curl -H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/api-configs/twitterResponse Example:
{
"id": 1,
"name": "twitter",
"url": "{env.TWITTER_URL}/x/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "TWITTER_API_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "en",
"socialify_image": false,
"default_json_body": "",
"updated_at": "2024-03-15T10:00:00Z"
}Endpoint: /api/api-configs
Method: POST
Description: Create a new API configuration for external integration.
Curl Example:
curl -X POST \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "bluesky",
"url": "{env.BLUESKY_URL}/bluesky/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "BLUESKY_SERVER_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "en",
"socialify_image": false,
"default_json_body": ""
}' \
http://localhost:8080/api/api-configsRequest Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique identifier for the API (alphanumeric, hyphens, underscores only) |
url |
string | Yes | The endpoint URL (supports {env.VAR} syntax) |
method |
string | Yes | HTTP method (GET, POST, PUT, DELETE, PATCH) |
auth_type |
string | No | Authentication type:bearer, api_key, or empty |
token_env_var |
string | No | Environment variable name containing the auth token |
token_header |
string | No | Header name for API key (required if auth_type is api_key) |
content_type |
string | Yes | Request content type:json or multipart |
timeout |
integer | Yes | Request timeout in seconds (must be > 0) |
success_code |
integer | Yes | Expected HTTP success code (100-599) |
enabled |
boolean | Yes | Whether the API is enabled |
response_type |
string | No | Expected response format |
text_language |
string | No | Language code for text content (e.g.,en, uk) |
socialify_image |
boolean | Yes | Whether to generate socialify images |
default_json_body |
string | No | JSON string of default key/value pairs (supports {env.VAR}) |
Request Example:
{
"name": "bluesky",
"url": "{env.BLUESKY_URL}/bluesky/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "BLUESKY_SERVER_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "en",
"socialify_image": false,
"default_json_body": ""
}Response Example:
{
"id": 3,
"name": "bluesky",
"url": "{env.BLUESKY_URL}/bluesky/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "BLUESKY_SERVER_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 30,
"success_code": 200,
"enabled": true,
"response_type": "json",
"text_language": "en",
"socialify_image": false,
"default_json_body": "",
"updated_at": "2024-03-15T10:00:00Z"
}Endpoint: /api/api-configs/{name}
Method: PUT
Description: Update an existing API configuration. All fields are optional - only provide the fields you want to update.
Curl Example:
curl -X PUT \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"enabled": false,
"timeout": 60
}' \
http://localhost:8080/api/api-configs/twitterRequest Parameters:
All fields are optional. Only include the fields you want to update.
| Parameter | Type | Description |
|---|---|---|
url |
string | The endpoint URL (supports {env.VAR} syntax) |
method |
string | HTTP method (GET, POST, PUT, DELETE, PATCH) |
auth_type |
string | Authentication type:bearer, api_key, or empty |
token_env_var |
string | Environment variable name containing the auth token |
token_header |
string | Header name for API key |
content_type |
string | Request content type:json or multipart |
timeout |
integer | Request timeout in seconds (must be > 0) |
success_code |
integer | Expected HTTP success code (100-599) |
enabled |
boolean | Whether the API is enabled |
response_type |
string | Expected response format |
text_language |
string | Language code for text content (e.g.,en, uk) |
socialify_image |
boolean | Whether to generate socialify images |
default_json_body |
string | JSON string of default key/value pairs (supports {env.VAR}) |
Request Example:
{
"enabled": false,
"timeout": 60,
"text_language": "es"
}Response Example:
{
"id": 1,
"name": "twitter",
"url": "{env.TWITTER_URL}/x/api/posts/create",
"method": "POST",
"auth_type": "api_key",
"token_env_var": "TWITTER_API_KEY",
"token_header": "X-API-Key",
"content_type": "multipart",
"timeout": 60,
"success_code": 200,
"enabled": false,
"response_type": "json",
"text_language": "es",
"socialify_image": false,
"default_json_body": "",
"updated_at": "2024-03-15T11:00:00Z"
}Endpoint: /api/api-configs/{name}
Method: DELETE
Description: Delete an API configuration.
Curl Example:
curl -X DELETE \
-H "Authorization: Bearer <API_TOKEN>" \
http://localhost:8080/api/api-configs/twitterResponse Example:
{
"status": "success",
"message": "API config deleted successfully"
}API Configuration Notes:
- Environment Variables: Use
{env.VARIABLE_NAME}syntax inurlanddefault_json_bodyfields to reference environment variables - Default JSON Body: For APIs with
content_type: json, you can specify default key/value pairs that are always included in requests. Store as a JSON string, e.g.,{"type": "chat", "jid": "{env.WAPP_JID}"} - Auto-Reload: After creating, updating, or deleting an API configuration, the system automatically reloads all configurations to apply changes immediately
- Migration: On first startup (v3.4.0+), existing configurations from
apis-config.ymlare automatically migrated to the database
Status Codes:
- 200: Success (GET, PUT)
- 201: Created (POST)
- 400: Bad Request - Invalid parameters or validation errors
- 401: Unauthorized - Invalid or missing Bearer token
- 404: Not Found - API configuration does not exist (GET, PUT, DELETE)
- 500: Internal Server Error - Database or server error