API & Agents
Versioned JSON API reference and agent onboarding workflow for RailsPress 1.3.x.
Overview
RailsPress exposes a versioned JSON API under /railspress/api/v1 for programmatic publishing workflows.
The API is opt-in. Enable it in your initializer before calling endpoints:
Railspress.configure do |config|
config.enable_api
config.current_api_actor_method = :current_user
end
Default v1 scope includes posts, imports, categories, and tags. API keys currently have full access to exposed v1 resources.
Authentication
RailsPress API uses bearer tokens managed from Agents & API in admin (/railspress/admin/api_keys).
Enable API auth wiring in your initializer:
Railspress.configure do |config|
config.enable_api
# Optional: include a host concern into Railspress::Admin::BaseController
# so current_user and auth guards are available in RailsPress admin.
# config.admin_auth_concern = "RailspressAdminAuth"
config.current_api_actor_method = :current_user
# Alternative when auth relies on request/session helpers:
# config.current_api_actor_proc = -> {
# user = Session.find_by(id: cookies.signed[:session_id])&.user
# user if user&.admin?
# }
# config.public_base_url = "https://blog.example.com"
end
If current_user is already available in RailsPress admin (Devise-style or via config.admin_auth_concern), current_api_actor_method = :current_user is the clean default.
Use current_api_actor_proc when your auth helper is not directly available on Railspress::Admin::BaseController.
Generated admin API/agent instruction snippets resolve base URL in this order:
config.public_base_url(if set)Rails.application.routes.default_url_options- Current request base URL
Route Constraints
If your host app mounts RailsPress behind an admin route constraint, allow API paths through the constraint. Otherwise agents will receive 404 before RailsPress API auth runs.
class AdminConstraint
def self.matches?(request)
return true if request.path == "/railspress/api" || request.path.start_with?("/railspress/api/")
session_id = request.cookie_jar.signed[:session_id]
return false if session_id.blank?
Session.includes(:user).find_by(id: session_id)&.user&.admin?
end
end
Rails.application.routes.draw do
constraints AdminConstraint do
mount Railspress::Engine => "/railspress"
end
end
Expected behavior:
/railspress/admin/*remains host-auth protected./railspress/api/*reaches RailsPress and then enforces bearer token auth (401without a token).
Two token types are available:
- API key (
rp_*) for direct content endpoint access. - Agent bootstrap key (
rpb_*) for one-time exchange atPOST /railspress/api/v1/agent_keys/exchange.
API and bootstrap secrets are encrypted with Active Record Encryption. Configure encryption keys in your app before using key management.
Prime Endpoint
Use prime as your first handshake after setting a bearer token. It confirms auth, capabilities, endpoint paths, and default publishing behavior.
$ curl -H "Authorization: Bearer $RAILSPRESS_TOKEN" \
http://localhost:3000/railspress/api/v1/prime
Prime reports that post creation defaults to draft unless post.status is explicitly set to published.
Posts API
Base path: /railspress/api/v1/posts
Endpoints:
GET /posts,GET /posts/:idPOST /posts,PATCH /posts/:id,DELETE /posts/:id- Nested header image, focal point, and context override endpoints when post images/focal points are enabled.
Create draft (default):
$ curl -X POST \
-H "Authorization: Bearer $RAILSPRESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"post":{"title":"API draft","content":"<p>Hello</p>"}}' \
http://localhost:3000/railspress/api/v1/posts
To publish on create/update, set post.status to published (and optionally post.published_at).
Post Imports API
Base path: /railspress/api/v1/posts/imports
Supported file extensions: .md, .markdown, .txt, .zip.
Submit import, then poll status:
$ curl -X POST \
-H "Authorization: Bearer $RAILSPRESS_TOKEN" \
-F "file=@./my-posts.zip" \
http://localhost:3000/railspress/api/v1/posts/imports
$ curl -H "Authorization: Bearer $RAILSPRESS_TOKEN" \
http://localhost:3000/railspress/api/v1/posts/imports/12
Categories & Tags API
Taxonomy endpoints are available at:
/railspress/api/v1/categories(index/show/create/update/destroy)/railspress/api/v1/tags(index/show/create/update/destroy)
Category deletion returns 422 if posts are still assigned. Tag deletion returns 204 when successful.
Admin Key Lifecycle
Manage keys from Agents & API:
- Create direct API keys (optional expiration, rotate, revoke).
- Create one-time bootstrap keys (default 1-hour expiration, revoke if unused).
- Copy generated quick-start instructions from one-time reveal screens.
Plaintext tokens are shown once at create/rotate/exchange time. Store immediately and rotate/revoke when needed.
Errors
All API errors return an error object. Validation failures include a details array.
| Status | Meaning |
|---|---|
401 Unauthorized |
Missing/invalid/revoked/expired token |
404 Not Found |
Resource missing or API disabled |
422 Unprocessable Content |
Validation failure or unsupported input |