Skip to content

Developers

API reference

Generated from the OpenAPI document, version 1.3.0. Base URL https://api.arm-age.com; every route needs a key with the scope it names.

01

Endpoints

The same document, machine-readable, for code generators and API tools: https://api.arm-age.com/v1/openapi.json.

The organization's stories, newest change first

GET/v1/storiesscope stories:read

Every story of the key's organization whatever its status (draft to published), with the current version's title and summary. Filter with status (comma-separated). Keyset pagination: pass next_cursor back as cursor. Scope stories:read. Cache-Control: private, no-store.

Parameters
NameInTypeDescription
statusquerystringComma-separated statuses to include: draft, ai_generated, review_required, approved, scheduled, publishing, published, failed, rejected, unpublished, archived.
limitqueryinteger
cursorquerystringThe next_cursor of the previous page.
Responses
StatusBodyWhen
200List of StoryA page of stories.
400ErrorUnknown status, limit outside 1-100 or a malformed cursor (invalid_parameters; error.fields).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/stories \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

One story with its body and decision history

GET/v1/stories/{id}scope stories:read

The current version's structured body and every recorded approval decision, newest first. Only decisions recorded by the approval credential are listed (ADR 0038). Scope stories:read.

Parameters
NameInTypeDescription
id (required)pathstring (uuid)
Responses
StatusBodyWhen
200StoryDetailThe story.
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
404ErrorNo story with this id in the key's organization (not_found).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/stories/<story id> \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

The approval queue: stories waiting for a decision

GET/v1/approvalsscope approvals:read

Stories in review_required, newest change first. Decisions are made by people in the Armage workspace (email and Slack approvals are planned), never by an API key: nothing publishes unapproved. Scope approvals:read.

Parameters
NameInTypeDescription
limitqueryinteger
cursorquerystringThe next_cursor of the previous page.
Responses
StatusBodyWhen
200List of StoryA page of waiting stories.
400ErrorLimit outside 1-100 or a malformed cursor (invalid_parameters).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/approvals \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

Published stories as JSON Feed 1.1 (for a CMS to pull)

GET/v1/feed.jsonscope feed:read

The 50 most recent published stories with plain-text and minimal escaped HTML bodies. Scope feed:read. For importers that cannot send headers, the key may be given as ?key= - only a key whose sole scope is feed:read.

Responses
StatusBodyWhen
200JSON Feed 1.1The feed (application/feed+json).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/feed.json \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

Published stories as RSS 2.0 (for a CMS to pull)

GET/v1/feed.xmlscope feed:read

The same 50 stories as /v1/feed.json, with content:encoded bodies. Scope feed:read; the same ?key= rule.

Responses
StatusBodyWhen
200—The feed (application/rss+xml).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/feed.xml \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

The organization's webhook endpoints

GET/v1/webhook_endpointsscope webhooks:read

Every endpoint, enabled or not, newest first; never its signing secret (only secret_hint, its last four characters). Endpoints are added, tested, disabled and re-enabled by an owner or admin in the Armage workspace. Scope webhooks:read.

Responses
StatusBodyWhen
200List of WebhookEndpointThe endpoints (one page).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/webhook_endpoints \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

The webhook delivery log, newest first

GET/v1/webhook_deliveriesscope webhooks:read

One row per event per endpoint: status (pending while retries remain, delivered, failed), attempts, the last HTTP status and a short error. Payloads are not kept. Filter with endpoint_id; keyset pagination as /v1/stories. Scope webhooks:read.

Parameters
NameInTypeDescription
endpoint_idquerystring (uuid)Only this endpoint's deliveries.
limitqueryinteger
cursorquerystringThe next_cursor of the previous page.
Responses
StatusBodyWhen
200List of WebhookDeliveryA page of deliveries.
400ErrorA malformed endpoint_id, limit outside 1-100 or a malformed cursor (invalid_parameters).
401ErrorNo key, a malformed, expired or revoked key, or a key for the other environment (missing_api_key, invalid_api_key, wrong_environment). WWW-Authenticate: Bearer.
403ErrorThe key lacks the scope this route needs (insufficient_scope).
429ErrorMore than 300 requests a minute for this key, or a flood from one client IP (too_many_requests). Retry-After: 60.
503ErrorThe client API is not configured in this environment (api_unavailable).
curl
curl https://api.arm-age.com/v1/webhook_deliveries \
  -H "Authorization: Bearer $ARMAGE_API_KEY"

02

Webhook events

Coming Armage POSTs these to your endpoint, signed. Setting up an endpoint and verifying a request: Webhooks.

Events
TypeBodyWhen
story.submittedWebhookEventA story was sent for review: it is now in the approval queue. Sent to every enabled endpoint subscribed to story.submitted, signed per Standard Webhooks.
story.approvedWebhookEventA person approved the current version of a story. Sent to every enabled endpoint subscribed to story.approved, signed per Standard Webhooks.
story.rejectedWebhookEventA person sent a story back with a note. Sent to every enabled endpoint subscribed to story.rejected, signed per Standard Webhooks.
story.publishedWebhookEventA story was published. Sent to every enabled endpoint subscribed to story.published, signed per Standard Webhooks.
story.unpublishedWebhookEventA published story was taken down. Sent to every enabled endpoint subscribed to story.unpublished, signed per Standard Webhooks.
webhook.testWebhookTestEventSent once when someone presses "Send test event" in the Armage workspace. Signed like every event; never recorded as a delivery and never retried.

03

Objects

Responses may gain fields without a new version: ignore fields you do not recognize. Timestamps are ISO 8601 with an offset.

Story

Fields
FieldTypeNotes
object"story"always present
idstringalways present
type"insight" | "press_release" | "announcement" | "in_the_news" | "event" | "video"always present
slugstringalways present
status"draft" | "ai_generated" | "review_required" | "approved" | "scheduled" | "publishing" | "published" | "failed" | "rejected" | "unpublished" | "archived"always present
titlestringalways present; may be null
summarystringalways present; may be null
versionintegeralways present; may be null
topicsstring[]always present
published_atstring (date-time)always present; may be null
created_atstring (date-time)always present
updated_atstring (date-time)always present

StoryDetail

Fields
FieldTypeNotes
object"story"always present
idstringalways present
type"insight" | "press_release" | "announcement" | "in_the_news" | "event" | "video"always present
slugstringalways present
status"draft" | "ai_generated" | "review_required" | "approved" | "scheduled" | "publishing" | "published" | "failed" | "rejected" | "unpublished" | "archived"always present
titlestringalways present; may be null
summarystringalways present; may be null
versionintegeralways present; may be null
topicsstring[]always present
published_atstring (date-time)always present; may be null
created_atstring (date-time)always present
updated_atstring (date-time)always present
bodyobject[]always present
approvalsApprovalDecision[]always present

ApprovalDecision

Fields
FieldTypeNotes
object"approval_decision"always present
idstringalways present
versionintegeralways present; may be null
decision"approved" | "rejected"always present
actor_typestringalways present
actor_rolestringalways present
notestringalways present; may be null
decided_atstring (date-time)always present

WebhookEndpoint

Fields
FieldTypeNotes
object"webhook_endpoint"always present
idstringalways present
urlstringalways present
events"story.submitted" | "story.approved" | "story.rejected" | "story.published" | "story.unpublished"[]always present
status"enabled" | "disabled"always present
disabled_reason"failing" | "by_client" | "by_armage"always present; may be null
secret_hintstringalways present
created_atstring (date-time)always present
updated_atstring (date-time)always present

WebhookDelivery

Fields
FieldTypeNotes
object"webhook_delivery"always present
idstringalways present
endpoint_idstringalways present
event_idstringalways present
event_type"story.submitted" | "story.approved" | "story.rejected" | "story.published" | "story.unpublished"always present
story_idstringalways present; may be null
status"pending" | "delivered" | "failed"always present
attemptsintegeralways present
last_status_codeintegeralways present; may be null
last_errorstringalways present; may be null
next_attempt_atstring (date-time)always present; may be null
created_atstring (date-time)always present
delivered_atstring (date-time)always present; may be null

WebhookEvent

Fields
FieldTypeNotes
idstringalways present. The event id; also the webhook-id header. Dedupe on it.
object"event"always present
type"story.submitted" | "story.approved" | "story.rejected" | "story.published" | "story.unpublished"always present
created_atstring (date-time)always present. When the story changed.
dataobjectalways present

WebhookTestEvent

Fields
FieldTypeNotes
idstringalways present
object"event"always present
type"webhook.test"always present
created_atstring (date-time)always present
dataobjectalways present

Error

Fields
FieldTypeNotes
errorobjectalways present

Build against a sandbox workspace

Or write