Storing activity history

Movement can model external events from other platforms, or from in-person activities, through activity history.

This means you can store data such as:

  • RSVPs and attendance to events
  • external contacts outside of Movement
  • actions from other platforms, such as petition signatures

This data can be structured, so the concept of an in-person event can be pushed in through the API, and then attendances to it by 1 or more supporters can be stored. This is useful as it is then queryable: a search can be built of everyone who attended an event.

The concepts in movement are 'Activities' and 'Activity Entities'. An Activity Entity represents an external concept, such as an event, or a petition. An Activity is then associated with an Activity Entity and a Target, forming the link between the 2.

Data imported via these methods can be seen within Movement on the profile page of supporters. It can also be queried via the API.

Movement is also able to create search filters to query this data in an easy way. If you'd like to enable this, please get in touch with support once you've structured your data and are ready to import it via the API.

Upserting

If you include the upsert parameter as true on activity records, Movement will attempt to update based on the external_id of the activity. This allows you to update activities pushed in, for example if an RSVP changes from 'confirmed' to 'tentative'.

Examples

Logging a contact via doorknocking

For a simple external contact or event, you can push an activity without an Activity Entity. For example, to log a doorknocking contact, you could use a payload such as:

curl --request POST \
     --url https://subdomain.yourmovement.org/api/activity \
     --header 'content-type: application/json' \
     --header 'Authorization: Bearer API_TOKEN' \
     --data '{
    "external_id": "MembershipNumber",
    "activities": [
        {
            "external_id": "DoorknockingContact1",
            "upsert": true,
            "topic": "doorknocking",
            "title": "Contacted via a doorknocking event",
            "source": "doorknocking_app",
            "body": "...",
            "happened_at": "2025-02-01T09:33:00Z"
        }
    ]
}'

Logging someone RSVPed to an event

Some activity data is best when linked to an Activity Entity, as this means it's easier to lookup all supporters who are related to an external event, such as a meeting, zoom call, or in-person event. Here's an example of pushing an activity linked to an Activity Entity:

curl --request POST \
     --url https://subdomain.yourmovement.org/api/activity \
     --header 'content-type: application/json' \
     --header 'Authorization: Bearer API_TOKEN' \
     --data '{
    "external_id": "MembershipNumber",
    "activities": [
        {
            "external_id": "RSVP_Event456_1",
            "upsert": true,
            "topic": "event_engagement",
            "title": "RSVP'\''d to Community Town Hall",
            "source": "event_platform",
            "body": "User confirmed attendance for the Community Town Hall event on March 15th",
            "happened_at": "2024-02-28T14:30:00Z",
            "entities": [
                {
                    "kind": "event",
                    "source": "EventPlatform",
                    "external_id": "EVT_456",
                    "name": "Community Town Hall - March 2024",
                    "metadata": {
                        "Location": "..."
                    },
                    "external_url": "https://events.example.com/community-town-hall-march-2024"
                }
            ]
        }
    ]
}'

Movement looks up Activity Entities by a combination of their source and external_id, so if other RSVPs have been imported prior to this API call, they'll be linked to the existing Activity Entity. This ensures you're not creating duplicate Activity Entities unless the source data is different.