Reference
Activity Sync examples

Alex Pribula
Alex Pribula
  • Updated

Concept: Activity
Concept: Activity Sync

What this document covers:

  • What are the types of activity: Learn about the various types of activities that Pendula emits, including messaging, experience lifecycle activity, and inbound message matching.
  • How activities are structured: Each activity is provided in a structured JSON format, which includes contextual data like the flow, experience, and additional custom information.
  • How to use these activities: These activities can be consumed by third-party systems for monitoring, reporting, or alerting purposes. By understanding the structure of each activity, you can create meaningful insights or automate actions based on them.

Workflow context

For every activity, there is what’s called workflowContext (object). The workflowContext object contains all the relevant contextual information for that activity:

  • The associated experience (experienceContext: experienceID)
  • The associated flow (flowContext: flowId, flowName, flowVersion)
  • The associated node within the flow (nodeContext: nodeId, nodeName, outputName)

While all activities include workflowContext, some are not fully populated yet (Inbound message unmatched, inbound message trigger). We are working to implement workflowContext consistently for all activities.

"workflowContext": {
"experienceContext": {
"experienceId": "501b95b3-06d3-4398-9ad4-b2563e158308"
},
"flowContext": {
"flowId": "b07a5e44-04e3-4698-a799-04c558b77147",
"flowName": "My first flow",
"flowVersion": 2
},
"nodeContext": {
"nodeId": "node-e72ur",
"nodeName": "Upsell Conversation",
"outputName": "conversation_2"
}

Custom context

Custom context consists of a set of configurable key-value pairs that can be added to all activities for experiences. To learn more about custom context in depth and how to use it, please visit this article.

Experience activity

experience-start

The very first activity for an experience is an experience-start activity:

{
"experienceId": "60b34d82-7781-474b-ad10-4bca1a774e14",
"timestamp": "2024-08-27T13:25:04.913Z",
"workflowContext": {...},
"customContext": {},
"kind": "experience-start"
}

experience-finish (outcome: success)

Here is a successful, ‘Complete’ experience-finish activity:

{
"experienceId": "60b34d82-7781-474b-ad10-4bca1a774e14",
"timestamp": "2024-08-28T13:40:13.482Z",
"outcome": {
"success": {
"value": {}
}
},
"workflowContext": {...},
"customContext": {},
"kind": "experience-finish"
}

experience-finish (outcome: failure)

Here is a failed, ‘Failed’ experience-finish activity. Before this activity, there may be other activities signalling what caused the experience to fail and finish (for instance, validation-failed for a message or bounce)

{
"experienceId": "60b34d82-7781-474b-ad10-4bca1a774e14",
"timestamp": "2024-08-28T14:12:52.134Z",
"outcome": {
"failure": {
"errorMessage": "Unhandled outcome for messaging/sendSenderIdSmsWithOutcome: failure/validation-error. Context: {\\"rawArgs\\":{\\"message\\":{\\"kind\\":\\"handlebars\\",\\"handlebars\\":\\"Activity Sync - Unmatched Trigger node - SENT outcome\\"},\\"senderId\\":{\\"kind\\":\\"handlebars\\",\\"handlebars\\":\\"PENDULA_TEST\\"},\\"recipientNumber\\":{\\"kind\\":\\"handlebars\\",\\"handlebars\\":\\"{{ unmatchedMessageTrigger_1.fromNumber }}\\"},\\"successTimeoutMins\\":{\\"kind\\":\\"number\\",\\"number\\":1}},\\"outputs\\":{\\"outcome\\":\\"failure\\",\\"outcomeReason\\":\\"validation-error\\",\\"timestamp\\":1724854371406},\\"args\\":{\\"message\\":\\"Activity Sync - Unmatched Trigger node - SENT outcome\\",\\"senderId\\":\\"PENDULA_TEST\\",\\"recipientNumber\\":\\"+61401260405\\",\\"successTimeoutMins\\":1},\\"type\\":\\"messaging/sendSenderIdSmsWithOutcome\\",\\"nodeId\\":\\"node-g2zkv\\"}",
"errorCode": "experiences/fail"
}
},
"workflowContext": {...},
"customContext": {},
"kind": "experience-finish"
}

experience-failed

And finally, here is an ‘Error’ experience-failed activity. If multiple of these activities are detected within a flow; the flow itself will be stopped and also set to status ‘Error’.

{
"experienceId": "ee4ee007-2bb2-41de-8da3-038cfe33564d",
"timestamp": "2024-09-04T00:05:23.443Z",
"workflowContext": {...},
"customContext": {},
"errorDetails": [
{
"errorMessage": "Not found: inboundWebhookTrigger_1 (full path: inboundWebhookTrigger_1.message). Available fields were: AvailableFields[inboundSMSTrigger_1.fromNumber:<+.10.5>,inboundSMSTrigger_1.matchedIntent:<m.8.d>,inboundSMSTrigger_1.matchedPart:<M.8.d>,inboundSMSTrigger_1.matchedType:<E.19.)>,inboundSMSTrigger_1.messageBody:<M.8.d>,inboundSMSTrigger_1.timestamp:<number>]",
"errorCode": null
}
],
"kind": "experience-failed"
}

Messaging events

A message being ‘queued’ is the first activity in the process of sending a message. The message queued activity contains all of the relevant information for the lifecycle of a message (recipient, message body, attachments etc) and generates a message ID.

Any subsequent activities (sent to gateway, delivered, opened, any failures etc) can all be correlated back to the initial queued activity using the message ID.

queued (SMS)

Here is a message queued activity for an SMS:

{
"messageId": "1d8e4e9c-69d8-4cd1-83fe-c13ef6870cfd",
"payload": {
"sender": "0000000000",
"recipient": "+61412345678",
"body": "Thanks for signing up, John.",
"segmentCount": 1,
"kind": "sms"
},
"timestamp": "2024-08-28T13:38:46.210055990Z",
"workflowContext": {...},
"customContext": {},
"kind": "queued"
}

queued (email)

Here is a message queued activity for an email:

{
  "messageId": "3064433f-d939-4df9-b49b-a2fa2573bce2",
  "payload": {
    "sender": "me@appleseed.com",
    "recipient": "john.smith@bananas.com",
    "subject": "Thanks for registering with us.",
    "body": "<hmtl>\\n <body>\\n Hello world!\\n </body>\\n</hmtl>",
    "plainTextBody": "\\n \\n Hello world!\\n \\n",
    "replyTo": "me@appleseed.com",
    "attachments": [
      {
        "filename": "welcomepack.pdf"
      },
      {
        "filename": "file2.png"
      }
    ],
    "kind": "email"
  },
  "timestamp": "2024-08-29T01:18:25.532229654Z",
  "workflowContext": {...},
  "customContext": {},
  "kind": "queued"
}

sent-to-gateway

Here is a message sent to gateway activity for SMS and email:

{
"messageId": "1d8e4e9c-69d8-4cd1-83fe-c13ef6870cfd",
"timestamp": "2024-08-28T13:38:46.434638837Z",
"workflowContext": {...},
"customContext": {},
"kind": "sent-to-gateway"
}

delivered

Here is a message delivered activity for SMS and email:

{
"messageId": "1d8e4e9c-69d8-4cd1-83fe-c13ef6870cfd",
"timestamp": "2024-08-28T13:38:52.362Z",
"workflowContext": {...},
"customContext": {},
"kind": "delivered"
}

opened

Here is a message opened activity for SMS and email:

{
"messageId": "3064433f-d939-4df9-b49b-a2fa2573bce2",
"timestamp": "2024-08-29T01:19:41.746Z",
"workflowContext": {...},
"customContext": {},
"kind": "opened"
}

bounced

Here is a message bounced activity for SMS and email:

{
"messageId": "ad45e9e3-e0ae-48f9-bdc0-e7c328a10b0b",
"errors": [
{
"errorMessage": "Bad request",
"errorCode": "explanation"
}
],
"timestamp": "2024-08-28T14:01:52.132Z",
"workflowContext": {...},
"customContext": {},
"kind": "bounced"
}

validation-failed

Here is an activity for when a message fails to send due to validation failing:

{
"messageId": "fb1ec07a-42ae-4b90-ae02-5b6cc8f6a2e3",
"errors": [
{
"errorMessage": "NonEmptyList(Recipient must be a valid phone number, got: Beepboop. )",
"errorCode": null
}
],
"timestamp": "2024-09-03T04:29:45.419079448Z",
"workflowContext": {...},
"customContext": {},
"kind": "validation-failed"
}

rejected-by-gateway

{
"messageId": "fb1ec07a-42ae-4b90-ae02-5b6cc8f6a2e3",
"errors": [
{
"errorMessage": "Rejected by gateway.",
"errorCode": null
}
],
"timestamp": "2024-09-03T04:29:45.419079448Z",
"workflowContext": {...},
"customContext": {},
"kind": "rejected-by-gateway"
}

Inbound messages & replies

inbound-matched-intent (trigger)

Here is a message inbound matched trigger activity (this happens after an experience-start activity):

Note that workflowContext is not fully populated: flowName and flowVersion

{
"messageId": "d3703474-8c92-4ee8-acf0-5353407bbc71",
"parentMessageId": "1d8e4e9c-69d8-4cd1-83fe-c13ef6870cfd",
"matchedIntentKey": "optin",
"matchedType": "Rule Match (Trigger)",
"matchedPart": "opt-in",
"body": "I'd like to opt-in",
"fromNumber": "+61412345678",
"timestamp": "2024-09-03T03:48:49.187411Z",
"workflowContext": {
"experienceContext": {
"experienceId": "6c36658f-6017-449e-9f91-3f23e3e9876a"
},
"flowContext": {
"flowId": "7d39b190-71fd-4295-9a48-1285f083de95",
"flowName": "?",
"flowVersion": 0
},
"nodeContext": {...}
},
"flowId": "7d39b190-71fd-4295-9a48-1285f083de95",
"customContext": {},
"kind": "inbound-matched-intent"
}

inbound-matched-intent (reply)

Here is a reply:

{
"messageId": "5ae77323-c8c5-4858-ac35-27798e98d6e9",
"parentMessageId": "e5cebadf-f1bc-4c2b-b892-f7ddd1bb3e59",
"matchedIntentKey": "upgrade",
"matchedType": "Rule Match (Conversation)",
"matchedPart": "upgrade",
"body": "I'd like to upgrade",
"fromNumber": "+61412345678",
"timestamp": "2024-09-03T04:27:52.953530Z",
"workflowContext": {...},
"flowId": "7d39b190-71fd-4295-9a48-1285f083de95",
"customContext": {},
"kind": "inbound-matched-intent"
}

inbound-unmatched

Here is a message inbound unmatched activity (this happens after an experience-start event):

Note that workflowContext is not fully populated: flowID, flowName and flowVersion

{
"messageId": "e46a9bce-f03e-4232-b68c-f27fce70a99f",
"payload": {
"sender": "+61487654321",
"recipient": "+61412345678",
"body": "I need some help",
"kind": "sms"
},
"timestamp": "2024-08-29T01:18:24.792807Z",
"workflowContext": {
"experienceContext": {
"experienceId": "60b34d82-7781-474b-ad10-4bca1a774e14"
},
"flowContext": {
"flowId": "?",
"flowName": "?",
"flowVersion": 0
},
"nodeContext": {...}
},
"customContext": {},
"kind": "inbound-unmatched"
}