Skip to main content

API Getting Started Guide

Everything you need to integrate with the ActRight API: authentication, endpoints, webhooks, and error handling.

EnvironmentProductionhttps://api.actright.com

Authentication

All API requests require a Bearer token in the Authorization header. There are two ways to authenticate:

Option A: API Key

Create an API key from your Dashboard → API Keys page. Keys are prefixed with gsk_ and can be scoped to read, read_write, or full access.

API Key authentication
curl https://api.actright.com/v1/petitions \
  -H "Authorization: Bearer gsk_your_api_key_here"

Option B: OAuth 2.0 Token

For apps that act on behalf of users, register an OAuth App and use the authorization code flow to obtain a JWT access token.

OAuth token authentication
curl https://api.actright.com/v1/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Security tip: Never commit API keys to source control. Use environment variables or a secrets manager. API keys with full scope can perform destructive actions.

Quick Start

List petitions

Request
curl https://api.actright.com/v1/petitions?limit=5 \
  -H "Authorization: Bearer gsk_your_key"
Response
{
  "data": [
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "title": "Save the Local Park",
      "slug": "save-the-local-park",
      "signatureCount": 1248,
      "signatureGoal": 5000,
      "status": "active"
    }
  ],
  "meta": { "total": 42, "limit": 5, "hasMore": true }
}

Sign a petition

Request
curl -X POST https://api.actright.com/v1/petitions/save-the-local-park/signatures \
  -H "Authorization: Bearer gsk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "I support this cause!",
    "isAnonymous": false
  }'
Response (201 Created)
{
  "data": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "petitionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "comment": "I support this cause!",
    "isAnonymous": false,
    "createdAt": "2026-02-10T12:00:00Z"
  }
}

Create a petition

Request
curl -X POST https://api.actright.com/v1/petitions \
  -H "Authorization: Bearer gsk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Improve Public Transit",
    "description": "<p>We need better bus routes in our city.</p>",
    "categoryId": "uuid-of-category",
    "signatureGoal": 1000,
    "tags": ["transit", "infrastructure"]
  }'
Response (201 Created)
{
  "data": {
    "id": "new-petition-uuid",
    "title": "Improve Public Transit",
    "slug": "improve-public-transit",
    "status": "draft",
    "createdAt": "2026-02-10T12:00:00Z"
  }
}

Petitions are created in draft status. Use POST /v1/petitions/:slug/publish to make them publicly visible.

Rate Limiting

API requests are rate limited per API key or access token to ensure fair usage for all developers.

50
Sustained requests/sec
100
Burst limit
429
Status when exceeded

Rate limit headers

Every response includes these headers so you can track your usage:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the window
X-RateLimit-ResetUnix timestamp when the window resets
429 Too Many Requests response
{
  "type": "https://api.groundswell.io/errors/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "You have exceeded 50 requests per second. Retry after 1.2s.",
  "instance": "/v1/petitions"
}

API Versioning

The ActRight API uses URL-based versioning. All endpoints are prefixed with the version number (e.g. /v1/).

Current version

The current API version is v1. Every response includes a version header:

Version response header
X-API-Version: 1

Versioning strategy

AspectPolicy
SchemeURL path prefix (/v1/, /v2/, etc.)
DeprecationEach major version is supported for 12 months after the next version is released
Breaking changesCommunicated via the developer changelog and deprecation headers
Additive changesNew fields and endpoints may be added to an existing version without a version bump

Tip: Always pin your integration to a specific version (e.g. /v1/). When a new version is released, test your integration against it before migrating.

Embed Widget

Embed any ActRight petition on your website using an iframe or the oEmbed protocol. The widget is fully responsive and supports theming.

iframe embed

Copy and paste the following HTML to embed a petition:

HTML
<iframe
  src="https://groundswell.io/embed/p/{slug}"
  width="100%"
  height="400"
  frameborder="0"
></iframe>

Replace {slug} with the petition slug (e.g. save-the-local-park).

oEmbed endpoint

Use oEmbed for CMS platforms and rich-preview tools:

oEmbed request
GET https://api.actright.com/v1/oembed?url=https://groundswell.io/p/{slug}&format=json

Theme support

The embed widget defaults to light mode. Append ?theme=dark for dark mode:

Dark mode embed
<iframe
  src="https://groundswell.io/embed/p/{slug}?theme=dark"
  width="100%"
  height="400"
  frameborder="0"
></iframe>

Responsive behavior

The widget automatically resizes its height via postMessage. To enable auto-resizing, add this listener on your page:

Auto-resize listener
window.addEventListener("message", (event) => {
  if (event.data?.type === "actright:resize") {
    const iframe = document.querySelector("iframe[src*='groundswell.io']");
    if (iframe) iframe.style.height = event.data.height + "px";
  }
});

WordPress: For WordPress sites, use the official ActRight plugin for a one-click embed experience. View WordPress docs

Webhook Events

Register webhook endpoints from your Dashboard → Webhooks page or via the API. ActRight will send POST requests to your URL for each subscribed event.

Event types

EventDescription
petition.createdA new petition has been created (draft).
petition.updatedPetition title, description, or settings were updated.
petition.publishedA petition was published and is now publicly visible.
petition.closedA petition was closed by its creator or an admin.
petition.victoryA petition was marked as victorious.
signature.createdSomeone signed a petition.
signature.milestoneA signature milestone was reached (e.g. 100, 500, 1000 signatures).
signature.removedA signature was removed by the signer or an admin.
update.createdThe petition creator posted an update.
payment.completedA payment (promotion or boost) was completed.
response.submittedA decision maker submitted an official response.
response.publishedA decision maker response was published.

Delivery headers

Each webhook delivery includes these headers:

HeaderDescription
X-ActRight-SignatureHMAC-SHA256 signature: sha256={hex}
X-ActRight-EventThe event type (e.g. signature.created)
X-ActRight-Delivery-IdUnique delivery UUID for deduplication
X-ActRight-TimestampISO 8601 timestamp of the event

Verifying signatures

Node.js verification example
import crypto from "crypto";

function verifyWebhook(payload, signature, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret)
      .update(payload)
      .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry policy: Failed deliveries are retried up to 5 times with exponential backoff. Your endpoint must respond with a 2xx status within 10 seconds to be considered successful.

Error Format

All error responses follow the RFC 7807 Problem Details specification. Every error includes a machine-readable type URI, a human-readable title, and the HTTP status code.

FieldTypeDescription
typestringURI identifying the error type
titlestringShort human-readable summary
statusnumberHTTP status code
detailstringDetailed explanation of the error
instancestringRequest path that generated the error
errorsarray?Field-level validation errors (422 responses)

Validation error (422)

{
  "type": "https://api.groundswell.io/errors/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "One or more fields are invalid.",
  "instance": "/v1/petitions",
  "errors": [
    { "field": "title", "message": "Required", "code": "invalid_type" },
    { "field": "description", "message": "String must contain at least 10 character(s)", "code": "too_small" }
  ]
}

Not found (404)

{
  "type": "https://api.groundswell.io/errors/not-found",
  "title": "Not found",
  "status": 404,
  "detail": "Petition with slug 'nonexistent' was not found.",
  "instance": "/v1/petitions/nonexistent"
}

Authentication error (401)

{
  "type": "https://api.groundswell.io/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Missing or invalid Bearer token.",
  "instance": "/v1/petitions"
}

API Playground

Try out API endpoints directly from this page. Enter your API key, select an endpoint, and send a request.

API Playground

Live
https://api.actright.com/v1/petitions

Ready to build?

Get an API key and start making requests in minutes.