Skip to content

For the complete documentation index, see llms.txt.

API triggers

API triggers let external systems request documentation updates from Promptless. Connect your CI/CD pipelines, custom automation tools, or any system that can make HTTP requests.

API triggers work well when you want to:

  • Integrate Promptless into CI/CD pipelines that run after deployments
  • Build custom automation workflows that trigger documentation updates
  • Connect external systems (ticketing, project management, custom tools) to Promptless
  • Programmatically request documentation updates without using Slack or the dashboard

API triggers are a built-in trigger type that’s always active when an API key exists, no YAML configuration required.

You create API keys from your dashboard, and each key authorizes requests for your whole organization. Only organization admins can create or revoke keys.

  1. Go to Settings > API Access.
  2. In the Create API key section, enter a Name that says what the key is for. A clear name lets you tell your keys apart when you revoke one later.
  3. Select Create key.
  4. Copy the secret from the Copy this key now section as soon as it appears. Promptless shows it only once.
  • No single active key: An organization can hold many API keys at once, each named for the integration that uses it.
  • Existing keys carry forward: If your organization already had an API key, it keeps working and appears in the list under the name Default.
  • Purpose-based names: Give each key a name that describes what it’s for, such as a CI pipeline, a Zapier connection, or a script. A separate key per integration lets you revoke or rotate that one key without touching the others. Do that after you retire that integration, or after a leak. Each active key needs a distinct name within your organization.
  • Independent revocation: Revoking or creating a key affects only that key; the others keep working. This replaces the earlier behavior, where regenerating the key logged out every other caller. Revoking is permanent. A revoked key can’t be restored, so move any caller still using it to another key first.
  • At-a-glance status: Each key in the list shows its Name and its key prefix (sk-pl-..., under the Key column). It also shows when it was Created and when it was Last used. Each key row has its own Revoke control; select it and confirm on that row to remove the key.

For the full request and response schemas, status codes, and an interactive explorer, see the API Reference. The sections below cover these endpoints with examples.

All requests use the base URL https://api.gopromptless.ai. The current API version is /v1. New integrations should use POST /v1/triggers; the unversioned POST /triggers is retained for callers built before versioning existed and runs the same operation through the same handler.

POST /v1/triggers

Include your API key as a Bearer token in the Authorization header:

Authorization: Bearer sk-pl-your-api-key

The bearer token determines which organization receives the trigger. There is no need to specify an organization ID in the URL.

Send a JSON body with your documentation instructions:

{
"instructions": "Update the getting started guide with the new authentication flow",
"context": {
"ticket_id": "ENG-123",
"requested_by": "deploy-bot"
}
}
FieldTypeRequiredDescription
instructionsstringYesWhat you want Promptless to document. Be specific about which docs to update and what changes to make.
contextobjectNoAdditional metadata to include with the request. This appears in trigger history for reference and is passed through to the workflow as additional context.
Terminal window
curl -X POST "https://api.gopromptless.ai/v1/triggers" \
-H "Authorization: Bearer sk-pl-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"instructions": "Document the new rate limiting feature added in v2.5",
"context": {
"release": "v2.5.0",
"jira_ticket": "DOC-456"
}
}'

A successful request returns a 202 Accepted response:

{
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"deduplicated": false
}

deduplicated is false for a fresh submission. It is true only when an Idempotency-Key matched an earlier submission, described next.

Send an optional Idempotency-Key request header to make a submission safe to retry. The key is a string of up to 255 characters.

  • A fresh submission returns a new trigger_event_id and "deduplicated": false.
  • A repeat submission that reuses a key already accepted returns the original trigger_event_id and "deduplicated": true, without creating a second trigger event.
  • Keys are scoped to your organization. Two organizations can use the same key string without affecting each other.
  • A failed submission (any 4xx or 5xx) does not consume the key, so you can retry it with the same key.
  • POST /triggers and POST /v1/triggers share one idempotency scope, so a key used on one path is recognized on the other.

Reuse a key only for retries of the same request. Reusing one key for two genuinely different requests silently discards the second and points its trigger_event_id at the first request’s task. Derive the key deterministically from the request’s content, for example a hash of instructions plus context. A genuine retry then reuses the same key, while two genuinely different requests get different keys.

Terminal window
curl -X POST "https://api.gopromptless.ai/v1/triggers" \
-H "Authorization: Bearer sk-pl-your-api-key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: deploy-2026-08-20-v2.5.0" \
-d '{
"instructions": "Document the new rate limiting feature added in v2.5"
}'

A repeat with the same key returns the original trigger event:

{
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"deduplicated": true
}
StatusErrorDescription
400invalid_idempotency_keyThe Idempotency-Key header is blank or longer than 255 characters.
400invalid_sinceThe since parameter is not a valid ISO 8601 timestamp.
400invalid_filterevent and status were combined in the same request.
401authentication_failedThe API key is missing, invalid, or revoked.
409org_not_configuredYour organization hasn’t finished setting up Promptless.
409no_eligible_doc_collectionNo configured doc collection is eligible to receive the request.
422Validation errorThe request body is invalid.
500enqueue_failedThe trigger could not be enqueued for processing.
503runtime_store_unavailableTrigger intake is temporarily unavailable.

invalid_since and invalid_filter come from the suggestions endpoint. The API enforces no rate limits today, so it never returns a 429.

The /v1 API also exposes read endpoints for polling integrations. They cover a connection check, the list of your doc collections, a suggestion lifecycle feed, and a finished-task feed. All take the same bearer token and return JSON. Each returns 401 when the key is missing, invalid, or revoked, and 503 when the read store is temporarily unavailable.

GET /v1/account

Returns the organization tied to your API key. Use it to test a connection and label the account. org_name is null for an organization created before names were recorded. For the full schema, see the Get account details reference.

Terminal window
curl "https://api.gopromptless.ai/v1/account" \
-H "Authorization: Bearer sk-pl-your-api-key"
{
"org_id": "org_2b5f9c1e",
"org_name": "Acme, Inc."
}
GET /v1/doc-collections

Lists the doc collections configured for your organization. Each entry carries its id, name, platform, and default_branch. The response is not paged. For the full schema, see the List doc collections reference.

Terminal window
curl "https://api.gopromptless.ai/v1/doc-collections" \
-H "Authorization: Bearer sk-pl-your-api-key"
{
"doc_collections": [
{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"name": "acme/docs",
"platform": "github",
"default_branch": "main"
}
]
}
GET /v1/suggestions

Returns the suggestion lifecycle feed for your organization. That feed covers the suggestions Promptless has created, merged, and closed. For the full schema, see the List suggestions reference.

Terminal window
curl "https://api.gopromptless.ai/v1/suggestions?event=merged&limit=50" \
-H "Authorization: Bearer sk-pl-your-api-key"
{
"suggestions": [
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"title": "Document the new rate limiting feature",
"description": "Add a rate limiting section to the API guide.",
"status": "merged",
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://app.gopromptless.ai/suggestions/7c9e6679-7425-40de-944b-e07fc1f90ae7",
"docs_pr_url": "https://github.com/acme/docs/pull/482",
"doc_collection_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"doc_collection_name": "acme/docs",
"impacted_file_paths": ["docs/api/rate-limits.md"],
"impacted_file_count": 1,
"created_at": "2026-08-20T14:32:00Z",
"merged_at": "2026-08-21T09:15:00Z",
"closed_at": null,
"closed_without_merge": false,
"close_reason": null
}
]
}

Each suggestion carries these fields:

FieldTypeDescription
idstring (UUID)Stable identifier for the suggestion. Deduplicate a feed on this value.
titlestring | nullShort summary of the documentation change.
descriptionstring | nullLonger explanation of the change.
statusstring | nullMirrors the docs pull request’s state: open, draft, merged, or closed. null when the suggestion is drafted but no docs PR has been opened yet; draft when a draft docs PR is open.
trigger_event_idstring (UUID) | nullIdentifier of the task that created the suggestion, the same id POST /v1/triggers returned. null for suggestions created before tasks were recorded.
urlstringDashboard link to the suggestion.
docs_pr_urlstring | nullLink to the documentation pull request, or null before a docs PR exists.
doc_collection_idstring | nullIdentifier of the collection the suggestion targets.
doc_collection_namestring | nullName of that collection.
impacted_file_pathsarray of stringPaths the suggestion changes.
impacted_file_countintegerNumber of impacted files.
created_atstringISO 8601 time the suggestion was created.
merged_atstring | nullISO 8601 time the docs PR merged, or null.
closed_atstring | nullISO 8601 time the suggestion closed, or null.
closed_without_mergebooleantrue when the suggestion closed without merging. Use this field to distinguish suggestions that shipped from ones that were rejected.
close_reasonstring | nullSupplementary machine-readable label for why the suggestion closed (for example, dashboard_review), or null. This set may expand over time and includes a catch-all such as unknown_legacy, so branch on closed_without_merge rather than hard-coding against close_reason values.

Narrow the feed with these query parameters, all optional:

ParameterValuesNotes
eventcreated, merged, closedSelects suggestions by lifecycle event and orders by that event’s timestamp.
statusopen, draft, merged, closedSelects suggestions by current status.
queryfree textMatches against the title and description.
sinceISO 8601 timestampInclusive lower limit on the event timestamp.
limit1–100Number of suggestions to return. Defaults to 50.
offset0 or greaterNumber of suggestions to skip. Defaults to 0.

event and status cannot be combined in the same request; sending both returns 400 invalid_filter. Use event to poll a lifecycle feed and status to search by current state.

Results come back newest-first, ordered by the selected event’s timestamp in descending order. Build an incremental loop against that order:

  • Track the newest event timestamp you have seen and pass it as since on the next poll, rather than a wall-clock “now”. Because since is an inclusive lower limit, this returns an event that committed a moment after your last poll instead of skipping it.
  • Since since is inclusive, a row whose event timestamp equals since is returned again. Deduplicate results by id.
  • Omitting since returns from the start of the available history.
  • Page through a large result set with limit and offset. A response that returns fewer than limit suggestions means you have reached the end of the current set.
  • event accepts only one value per request and cannot be combined with status. The full lifecycle covers created, merged, and closed-without-merge. Track it by running a separate polling loop with its own since cursor for each event value.
  • There is no cursor token; polling is driven entirely by since, limit, and offset.

A minimal incremental loop for one event value:

# Run one loop per event value (created, merged, closed).
since = null # omitted on the first poll -> full history
seen = set() # ids already handled, for dedup
repeat on an interval:
offset = 0
newest = since
while true:
page = GET /v1/suggestions?event=merged&limit=100&offset=offset
(add "&since=<since>" when since is set)
for s in page.suggestions: # newest-first
if s.id not in seen:
process(s)
seen.add(s.id)
newest = max(newest, s.merged_at)
if len(page.suggestions) < 100: # fewer than limit -> end of set
break
offset = offset + 100
since = newest # inclusive lower bound for next poll
GET /v1/triggers

Lists your organization’s finished tasks, newest completion first, including tasks that made no documentation change. For the full schema, see the List finished tasks reference.

Only finished tasks appear in this feed. A task still running has no outcome yet, so follow one in flight with GET /v1/triggers/{trigger_event_id}. The feed omits Promptless’s internal re-runs. If Promptless reopens a finished task to rework it, the task appears again when it finishes, with a new finished_at and possibly a different outcome.

Terminal window
curl "https://api.gopromptless.ai/v1/triggers?source=api&limit=50" \
-H "Authorization: Bearer sk-pl-your-api-key"
{
"tasks": [
{
"trigger_event_id": "d3aa7c40-5ec4-48c6-8d10-81c2ee042690",
"source": "api",
"request": "API: Update the retry documentation",
"outcome": "no_change_needed",
"resolution": "The retry guide already documents the new backoff, so no change was needed.",
"submitted_at": "2026-08-24T10:00:00+00:00",
"finished_at": "2026-08-24T10:18:00+00:00"
}
]
}

Each task carries these fields:

FieldTypeDescription
trigger_event_idstring (UUID)The task’s id, the same id POST /v1/triggers returned.
sourcestringThe task’s origin, such as api.
requeststring | nullA one-line summary of the submitted request.
outcomestring | nullHow the task ended. See Outcomes.
resolutionstring | nullA note that explains how the task ended.
submitted_atstringISO 8601 time the task was submitted.
finished_atstringISO 8601 time the task finished.

outcome is one of these values:

ValueMeaning
suggestions_createdThe task produced at least one suggestion.
no_change_neededThe task produced none because the docs already cover the change.
needs_inputThe task produced none and ended on a question the customer must answer. A later answer starts a new task.
failedPromptless could not finish the work.

outcome is null for tasks that finished before Promptless added the field and for tasks from sources other than the API or MCP. Promptless may add values later, so handle values not listed here.

This feed omits the suggestions a task produced. Each suggestion in the Suggestions feed carries trigger_event_id, so join the two feeds on that field.

Narrow the feed with these query parameters, all optional:

ParameterValuesNotes
sinceISO 8601 timestampInclusive lower limit on the completion timestamp. A trailing Z is accepted, and a value without a timezone is read as UTC.
sourcetrigger sourceExact source to return, such as api. Omit to return every source.
limit1–100Number of tasks to return. Defaults to 50.
offset0 or greaterNumber of tasks to skip. Defaults to 0.

An invalid since returns 400 invalid_since.

Poll this feed the way you poll the Suggestions feed, ordered by when each task completed:

  • Results come back newest-completion-first, ordered by completion timestamp and then by id.
  • Track the newest finished_at you have seen and pass it as since on the next poll. Because since is an inclusive lower limit, a task that finishes a moment after your last poll comes back on the next one.
  • Since since is inclusive, a task whose finished_at equals since comes back again. Deduplicate by trigger_event_id and finished_at together. A reopened task that finishes again keeps its trigger_event_id but carries a new finished_at, so deduplicating on the pair keeps its latest outcome instead of discarding it.
  • Page through a large result set with limit and offset. A response with fewer than limit tasks means you have reached the end of the current set.
  • A task finishing mid-poll moves rows to a higher offset, so a walk by offset returns it on a later page.

After you submit a task, follow its progress and continue the conversation on the same trigger event. Both operations use the same Authorization: Bearer sk-pl-... token. The conversation is available for tasks submitted over the API or MCP and for tasks created through MCP request_changes.

GET /v1/triggers/{trigger_event_id}

trigger_event_id is the id returned by POST /v1/triggers. A successful request returns 200 OK with the task’s current state:

FieldTypeDescription
trigger_event_idstring (UUID)The task’s id.
statusstringThe task’s current status. The status string can change over time, so branch on finished to detect completion.
finishedbooleantrue when the task has completed or been skipped.
submitted_atstringISO 8601 time the task was submitted.
sourcestringThe task’s origin.
requeststring | nullA one-line summary of the submitted request.
resolutionstring | nullA note that explains how the task ended. Read it after finished is true.
outcomestring | nullHow the task ended. See Outcomes for the values. null until the task finishes, and for tasks from sources other than the API or MCP.
suggestionsarrayA per-task summary of each suggestion this task produced, with the fields listed below. This is a lighter shape than the Suggestions feed.
status_guidancestringHuman- or LLM-readable advice for polling the task and interpreting its outcome. Key on finished, a boolean, to detect completion. Do not parse status_guidance in code.
messagesarrayThe persisted conversation, latest 100, oldest-first. Reading the conversation never consumes it.

Each entry in suggestions carries these fields:

FieldTypeDescription
idstring (UUID)Stable identifier for the suggestion.
titlestring | nullShort summary of the documentation change.
descriptionstring | nullLonger explanation of the change.
statusstring | nullThe docs pull request’s state: open, draft, merged, or closed. null before a docs PR exists.
doc_collection_idstring (UUID) | nullIdentifier of the collection the suggestion targets.
docs_pr_urlstring | nullLink to the documentation pull request, or null before a docs PR exists.
branch_namestringThe git branch in the documentation repository.
labelsarray of stringLabels on the suggestion.
assigneesarray of stringAssignees on the suggestion.
created_atstringISO 8601 time the suggestion was created.

The suggestions array lists the suggestions this task produced with their current status and docs pull request link. To track a suggestion’s full lifecycle, including whether it merged or closed without merging, use the Suggestions feed and its closed_without_merge field.

Each entry in messages has the TaskMessage shape below. The send endpoint returns the same shape.

FieldTypeDescription
idstring (UUID)Stable, immutable identifier. Deduplicate on it.
trigger_event_idstring (UUID)The task this message belongs to.
sequenceintegerThe message’s order within the task.
authorobjecttype is promptless or customer. name is the customer’s email when available, otherwise null.
created_atstringISO 8601 time the message was created.
messagestringThe message text.

Reading status works for any task source. Promptless populates the messages array for tasks submitted over the API or MCP and for tasks created through MCP request_changes. A task you submit over the API is eligible for a conversation. An empty messages array on your own API task means the task has no messages yet. Tasks from other sources, such as Slack, a GitHub pull request, or the dashboard, carry no conversation, so their messages array is empty.

Terminal window
curl "https://api.gopromptless.ai/v1/triggers/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk-pl-your-api-key"
{
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "in_progress",
"finished": false,
"submitted_at": "2026-08-20T14:32:00Z",
"source": "api",
"request": "Document the new rate limiting feature added in v2.5",
"resolution": null,
"outcome": null,
"suggestions": [
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"title": "Document the new rate limiting feature",
"description": "Add a rate limiting section to the API guide.",
"status": "open",
"doc_collection_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"docs_pr_url": "https://github.com/acme/docs/pull/482",
"branch_name": "promptless/document-rate-limits",
"labels": ["documentation"],
"assignees": ["deploy-bot@acme.com"],
"created_at": "2026-08-20T14:35:00Z"
}
],
"status_guidance": "Keep polling until finished is true.",
"messages": [
{
"id": "b1e2c3d4-5678-90ab-cdef-1234567890ab",
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"sequence": 1,
"author": { "type": "customer", "name": "deploy-bot@acme.com" },
"created_at": "2026-08-20T14:32:05Z",
"message": "Document the new rate limiting feature added in v2.5"
}
]
}

Poll this endpoint on an interval until finished is true. Back off and retry on a 503. When you read the conversation, deduplicate messages by their stable id so a repeated poll does not reprocess one.

For the full schema, see the Get task status reference.

POST /v1/triggers/{trigger_event_id}/messages

Promptless appends the message to the original task named by trigger_event_id. The reply stays on that task’s conversation, and no new task is created.

FieldTypeRequiredDescription
messagestringYesThe instruction to add. Non-empty after trimming, up to 20,000 characters.

Send an optional Idempotency-Key request header, up to 255 characters, to retry safely. The same key with the same text returns the original stored message with deduplicated set to true. The same key with different text returns 409 idempotency_conflict. The key is scoped to the task and your API key, so the same key value used on a different task is independent.

A new message returns 201 Created with body { "message": <TaskMessage>, "deduplicated": false }. An idempotent replay returns 200 OK with body { "message": <original TaskMessage>, "deduplicated": true }.

Terminal window
curl -X POST "https://api.gopromptless.ai/v1/triggers/550e8400-e29b-41d4-a716-446655440000/messages" \
-H "Authorization: Bearer sk-pl-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"message": "Also document the 429 rate-limit response for this endpoint."
}'
{
"message": {
"id": "c2f3d4e5-6789-01bc-def2-34567890abcd",
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"sequence": 2,
"author": { "type": "customer", "name": "deploy-bot@acme.com" },
"created_at": "2026-08-20T14:40:00Z",
"message": "Also document the 429 rate-limit response for this endpoint."
},
"deduplicated": false
}

A retry that sends the same text with the same Idempotency-Key returns the stored message and sets deduplicated to true:

{
"message": {
"id": "c2f3d4e5-6789-01bc-def2-34567890abcd",
"trigger_event_id": "550e8400-e29b-41d4-a716-446655440000",
"sequence": 2,
"author": { "type": "customer", "name": "deploy-bot@acme.com" },
"created_at": "2026-08-20T14:40:00Z",
"message": "Also document the 429 rate-limit response for this endpoint."
},
"deduplicated": true
}

For the full schema, see the Send a task message reference.

Both operations return 401 authentication_failed when the key is missing, invalid, or revoked. Both return 404 task_not_found for an unknown task or one in another organization. Both return 503 runtime_store_unavailable when the read store is temporarily unavailable.

StatusErrorDescriptionApplies to
404task_not_foundUnknown task, or a task in another organization.both
422Validation errorThe trigger_event_id in the path isn’t a valid UUID, or the request body is malformed.both
409task_finishedThe task has finished and stops accepting messages. A task that finished by reporting a blocker or a clarification request has still finished. To continue the work, submit a new trigger with POST /v1/triggers.send
400unsupported_task_sourceTask messages are available for tasks submitted over the API or MCP and for MCP request_changes tasks. Read the task’s status with GET /v1/triggers/{trigger_event_id} (status is available for every source), or submit the work as a new API trigger to converse.send
400invalid_messageThe message is empty or longer than 20,000 characters after trimming, or an Idempotency-Key that is blank or longer than 255 characters.send
409idempotency_conflictThe same Idempotency-Key was reused with different text.send
401authentication_failedThe API key is missing, invalid, or revoked.both
503runtime_store_unavailableTask intake or lookup is temporarily unavailable.both

API-triggered events appear in your dashboard with an API Task pill. A task that reaches the API through a Promptless-built client carries that client’s own pill. A task submitted through the Promptless Zapier app shows a Zapier Task pill. A task submitted from your editor over MCP shows an MCP Task pill.

View all API triggers on the Triggers page. API triggers show the submitted instructions and any context you included in the request.

Set the Trigger source filter to “API” on the Suggestions list to see documentation suggestions that came from API requests.

When you submit an API request:

  1. Validation: Promptless validates your API key and request format.
  2. Routing: The request is routed to your configured doc collections.
  3. Processing: Promptless analyzes your instructions along with configured context sources.
  4. Suggestion Creation: If documentation updates are needed, Promptless creates suggestions.