The ActionKit REST API allows you to access ActionKit programatically using HTTPS and JSON.

All API access is over HTTPS, and accessed from the following base:

Any HTTP client in any programming language should be able to interact with the API.


Requests to ActionKit's REST API require authentication using HTTP Basic Auth.


There are a few Resources that don't require Authentication. For example, Generic Action Processing.

The user is a user account from the list of staff users. We recommend creating staff accounts that are dedicated to API use. You can connect with the standard account password.

You can use the Permissions Groups to grant access to the REST API. To grant access to all objects in the database, add an account to the "All Models - View, Edit, and Delete" group. However, for security it's preferable to restrict an account's access to just the kinds of objects it will need.

You can test if an account has view access to a particular resource in the API by loading a URL like:

https://{User}:{Password}@[ YOUR ACTIONKIT HOSTNAME ]/rest/v1/

Resource List

You can browse the API at /rest/v1/ to see the full list of resources. Each resource listed includes the URI of a list endpoint and a schema, like so:

'action': { 'list_endpoint': /rest/v1/action/,
            'schema': /rest/v1/action/schema/},


A collection (a.k.a. a list endpoint) resource returns a list of representations. Collections have two top level keys: meta and objects. The metadata has a count of the total objects in the collection, links for the next and previous pages of objects, and the limit and offset used for this set of objects.

The limit and offset parameters are named _limit and _offset to avoid conflicts with object fields.

You can filter collections using query string arguments. You can filter on the fields listed in 'filtering' in the schema. Keys are the field name, values are the list of valid operators. "all" means any operator, "all with relations" means any operator on this field and the fields of the related resource.

Read more about filtering and ordering.


A single object resource (a.k.a. a detail endpoint) returns all the details about a single object. You can use the schema to see what fields will be included. The returned resource may include references to other resources.


Schemas describe resources. You can discover the type of data a field contains, as well as the methods allowed on the list and detail endpoints for the resource type. Here are the fields listed in each schema:

Field Description
allowed_detail_http_methods GET, POST, PATCH, PUT, DELETE
allowed_list_http_methods GET, POST (PATCH, PUT and DELETE are never allowed on list resources)
default_format 'application/json'
default_limit 20
fields A list of fields, with attributes such as the basic type the field uses
filtering A list of searchable fields, with the allowed operators for searching each field. ALL means you can filter on all of the Django QuerySet field lookups. ALL WITH RELATIONS means you can filter on the fields of the related resources as well. See the Django docs for the full list of field lookups. Read more about filtering.

The resources and fields generally correlate to tables and columns in your ActionKit database. You can sometimes find more information about a resource or field by looking at the Database Reference.

For example, the action resource corresponds to the core_action table.

HTTP Methods

Method Description
GET Used for retrieving resources.
POST Used for creating resources.
PATCH Used for updating resources with partial JSON data. A PATCH request may accept one or more of the attributes to update the resource.
PUT Used for replacing resources entirely.
DELETE Used for deleting resources.

Field Attributes

For each data field, you will see a set of attributes that help describe the field.

Attribute Description
blank Indicates whether data can be omitted from the field.
default Provides the default value for the field when no value has been set.
help_text A human-readable description of the field.
nullable Indicates whether null is an allowable value for the field.
primary_key Indicates if the field is a primary key for the object.
readonly Indicates if a POST, PATCH or PUT can alter the value of this field.
type Data type of the field. See Tastypie Field Types.
unique Indicates if the field is a unique identifier for the object.
verbose_name The long form of the field name.

Request Formats

ActionKit looks at the Content-Type header to decide how to parse any data sent in the request. The same request can be represented in JSON or XML. Your requests should include a Content-Type header with a value of 'application/xml' or 'application/json'.

XML requests should use a root element named request: '<request type="hash"></request>'. XML responses have a root element of response or object.

All requests must be encoded in UTF-8.

If there are other formats you'd like to see, please let us know.

Read more about Requests.

Response Formats

ActionKit looks at the Accept header to decide how to format responses. You can also use a format parameter in the query string to request a specific format. If the request query string includes a callback parameter, ActionKit will always return a JSONP callback.

We support the following formats. The Accept header uses the mime-types, the format parameter uses the names on the left, e.g. 'jsonp':

json  : application/json
jsonp : text/javascript
xml   : application/xml
html  : text/html
form  : text/html

We recommend using JSON.

Here's an example of a request using the Accept header to format the response in JSON:

$ curl -i -u user:password -H 'Accept: application/json' https://docs.actionkit.com/rest/v1/list/
HTTP/1.1 200 OK
Date: Tue, 20 Mar 2012 12:06:43 GMT
Vary: Cookie,Accept-Encoding,User-Agent
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
    "meta": {
        "previous": null,
        "total_count": 1,
        "offset": 0,
        "limit": 20,
        "next": null
    "objects": [
            "name": "Main email list",
            "created_at": "2012-03-14T09:06:01",
            "updated_at": "2012-03-14T09:06:01",
            "is_default": false,
            "hidden": false,
            "resource_uri": "/rest/v1/list/1/"

And here's an example of a request using the format parameter in the query string. This time we'll ask for xml:

$ curl -i -u user:password 'https://docs.actionkit.com/rest/v1/list/?format=xml'
HTTP/1.1 200 OK
Date: Tue, 20 Mar 2012 12:08:06 GMT
Vary: Cookie,Accept-Encoding,User-Agent
Content-Type: application/xml; charset=utf-8
Transfer-Encoding: chunked
<?xml version="1.0" encoding="utf-8"?>
  <objects type="list">
      <name>Main email list</name>
      <is_default type="boolean">False</is_default>
      <hidden type="boolean">False</hidden>
  <meta type="hash">
    <next type="null"/>
    <total_count type="integer">1</total_count>
    <previous type="null"/>
    <limit type="integer">20</limit>
    <offset type="integer">0</offset>

Response Codes

Response codes used by ActionKit are summarized below. Refer to https://tools.ietf.org/html/rfc7231#section-6 for the canonical definitions.

GET Responses

Response Status Code Description
200 OK The request was successful and the response body contains the representation requested.
301 MOVED PERMANENTLY A common redirect response to the canonical URI for the representation of the resource. You can GET the representation at the URI in the Location response header.
302 FOUND A common redirect response; you can GET the representation at the URI in the Location response header.
304 NOT MODIFIED Your client's cached version of the representation is still up to date.
401 UNAUTHORIZED The supplied credentials, if any, are not sufficient to access the resource.
404 NOT FOUND Resource not found.
429 TOO MANY REQUESTS Your application is sending too many simultaneous requests.
500 SERVER ERROR We couldn't return the representation due to an internal server error.
503 SERVICE UNAVAILABLE We are temporarily unable to return the representation. Please wait for a bit and try again.

POST / PUT Responses

Response Status Code Description
200 OK The request was successful, we updated the resource and the response body contains a representation.
201 CREATED The request was successful, we created a new resource and Location header contains the URI of the new resource.
202 ACCEPTED The request was successful, we updated the resource. (PATCH only)
204 NO CONTENT The request was successful, we updated the resource. (PUT only)
400 BAD REQUEST The data given in the POST, PATCH, or PUT failed validation. Inspect the response body for details.
401 UNAUTHORIZED The supplied credentials, if any, are not sufficient to create or update the resource.
404 NOT FOUND Resource not found.
405 METHOD NOT ALLOWED You can't POST, PATCH, or PUT to the resource.
429 TOO MANY REQUESTS Your application is sending too many simultaneous requests.
500 SERVER ERROR We couldn't create or update the resource. Please try again.

DELETE Responses

Response Status Code Description
204 OK The request was successful; the resource was deleted.
401 UNAUTHORIZED The supplied credentials, if any, are not sufficient to delete the resource.
404 NOT FOUND Resource not found.
405 METHOD NOT ALLOWED You can't DELETE the resource.
429 TOO MANY REQUESTS Your application is sending too many simultaneous requests.
500 SERVER ERROR We couldn't delete the resource. Please try again.

Filtering And Ordering

The fields and operators in filtering and ordering are based on the Django QuerySet syntax. The schema for each resource lists the fields on which you can filter under 'filtering', and on which you can order under 'ordering'. Fields sent as parameters in they querystring will be used for filtering, if they are fields on the resource. Ordering will check for an 'order_by' parameter in the querystring.


Filters will be extracted from URL query strings using the same double-underscore syntax as the Django ORM:



There is more documentation of the syntax in the django docs:

You can tell which fields you are allowed to filter on by looking at the schema for a resource. Fields are listed in the "filtering" section. The values can be a matching operator from the Django sytanx (e.g. startswith, exact, lte, contains), ALL, and ALL_WITH_RELATIONS. ALL means all operators are permitted on the field. ALL_WITH_RELATIONS means you can also search on the related fields values, use a double underscore between the field on the object your are searching and the field on the related object.

Fields are combined with a logical AND.


By default, filtering will use an exact match (which is case-insensitive):

But you can also search for values that contain the string:

Or, if you want to only match lower-case "rob" and ignore Rob and ROB, you can use the case-sensitive version:

Or start with the search:

If the field allows it, you can search on the related objects:

This may be especially useful in places where the names of related objects are meaningful:

Use '&' to combine fields, so to find pre-2015 pirates pages:

You can find pages tagged both "pirates" and "musical" with:

If you want to get a subset by IDs, you can do this if filtering using "in" is allowed:

An alternative, which can be useful for resources that don't allow "in", but do allow GET, is this:


To order the results, use the "order_by" parameter in your GET requests. Ordering works with the field name for ascending ordering and prefixed by - for descending. Fields on which you can order are listed in the 'ordering' section of the schema.



Usually you'll only be able to order on created_at and id - which is somewhat silly since they will almost always return the same order.

You can only order results on a single field.

The maximum number of objects returned per request is 100. Use paging to get more objects. The paging parameters are prefixed with "_" to avoid naming conflicts with columns. Use _limit and _offset.

High Level APIs

We've added a few high level APIs and methods to provide short cuts for certain common usecases or extended functionality.

  • Generic Action Processing handles all action creation.
  • The Donation Push API streamlines the process of sending externally processed donations to be recorded in your ActionKit database.
  • The Mailer API provides tools for creating, targeting, proofing and sending mailings.
  • Reports can be run synchronously or asynchronously using the /run/ and /background/ methods for the report resource.
  • The upload resource has a /stop/ method.
  • The usermerge endpoint creates a user merge job to combine records from two or more users.
  • The eraser endpoint is used to delete user data.
  • The salesforcemap endpoint is used to manage users in the Salesforce sync.

Action Processing

Almost all user actions should be created by via generic action processing. The action processor provides validation for actions of all types, such as checking that starts_at is in the future when creating events. And some ActionKit features such as "Act as Host" don't work without an eventcreateaction, which is only created via generic action processing.

You can create Actions by POSTing to the collection of Actions, i.e. the list_endpoint for the Action resource: /rest/v1/action/.

The only required parameters for action processing are page - the name of the Page - and user email. However, there are many other parameters to control processing and collect information from users.

POSTing to the generic action collection is like submitting a form from the cms or a page hosted outside of ActionKit. You can submit actions as JSON, XML, or x-www-form-url-encoded data.


We've reserved POSTing to the specific Action endpoints, e.g. /rest/v1/signupaction/, for a more RESTful implementation. For now, posting to a typed action endpoint will return an error.

You can process actions without authenticating. This is very similar to submitting a form in a page hosted on the ActionKit CMS or on your servers. The response from ActionKit will contain more information if the connection is authenticated.

Read more about Generic Action Processing.

Creating Pages

Action pages are created in a three step process, mimicking the process of creating pages through the ActionKit admin.

Step 1: Create a page against the page type-specific endpoint

The minimum required field is "name" -- and page names must be unique, so if you try to send the name of a page that has already been created, you'll get an error for the response.

Here's an example:

POST /rest/v1/petitionpage/

  "fields": {
    "custompagefield1": "First custom page field value",
    "custompagefield2": "Second custom page field value"
  "name": "climate-change",   // required
  "required_fields": [
      "id": "2",
      "name": "zip",
      "resource_uri": "/rest/v1/formfield/2/"
      "id": "11",
      "name": "name",
      "resource_uri": "/rest/v1/formfield/11/"
  "title": "Climate Change Is Real",
  "tags": [
      "name": "climate",
      "resource_uri": "/rest/v1/tag/1/"

Step 2: Create a page type-specific form

This is analogous to the "Edit Content" screen when setting up pages through the ActionKit admin.

Each page type will have different required fields for the form, but for all page types, be sure to set the "page" field to the URI of the page created in step 1. All pages will also require the "thank_you_text" field.

Continuing our example:

POST /rest/v1/petitionform/

  "about_text": "Let me tell you about the issue.",
  "page": "/rest/v1/petitionpage/1234/",    // required for all page types
  "statement_leadin": "Tell the President:",
  "statement_text": "Climate change is real.",
  "thank_you_text": "Thanks for signing."   // required for all page types

Step 3: Create a page followup object

POST to the pagefollowup list endpoint. This object contains the settings for the "After-action info" screen in the ActionKit admin.

As in step 2, set the "page" field to the URI of the page created in step 1, and you also need to set the after-action redirect URL in the "url" field:

POST /rest/v1/pagefollowup/

  "page": "/rest/v1/petitionpage/1234/",  // required
  "email_body": "Thanks for signing, now please share by forwarding this message to your friends.",
  "email_from_line": "/rest/v1/fromline/1/",
  "email_subject": "You're almost done.",
  "email_wrapper": "/rest/v1/emailwrapper/1/",
  "send_email": true,
  "send_taf": false,
  "share_description": "We're almost out of time to save the planet.",
  "share_image": "https://climate.nasa.gov/system/internal_resources/details/original/103_shutterstock_88550854-740px.jpg",
  "share_title": "Sign and share: Climate change is real.",
  "url": "/cms/thanks/my-test-page/"      // required