Sending Engagements from your server

Detailing the request format and supported action types with examples for sending purchase events, post-purchase events, and impressions

Promoted supports a variety of engagements as well as custom actions.

Your servers can log records using Promoted's Metrics API. The Metrics API accepts LogRequest proto messages as JSON HTTP requests.

This is useful when:

  • Logging purchase actions securely from your server.
  • If you are trying to reuse existing log streams. Promoted recommends using our client-side SDKs directly (includes better utilities and less likely to have errors).

Table of Contents

SectionDescription
Request formatThe JSON format of sending events using action
Required and optional fieldsAction usually requires the content_id, userInfo.userId, and actionType, with other optional fields
Sending purchase and other standard eventsSending navigate, like, checkout, purchase, and other actions
Sending post-purchase eventsPost-purchase events include cancelations, modifications, completion confirmations (e.g., "order delivered"), and other custom events for your marketplace
Sending impressionsPromoted supports sending impressions from your server
Action typesA list of the action types supported

Request format

Events are sent via Action on the LogRequest message. This usually requires the contentId, userInfo.userId, and actionType. Other fields are optional.

Any value-related fields and custom properties are set on properties.struct. This is especially beneficial for complex actions, such as order mutations, and it may also be useful for debugging. Promoted joins these fields with the content in the backend. Do not add any sensitive or personally identifiable information. If you want to include sensitive fields or are unsure which fields to add, contact Promoted. See more details on the required and optional fields, as well as an example, below.

Format

Here is the record format for sending events to Promoted via Action and the LogRequest message:

{
  action: [
    {
      userInfo: {
        userId: '...'
      },
      timing: {
        clientLogTimestamp: '...'
      },
      actionType: '...',
      contentId: '...',
      properties: {
        struct: {
          customKey: '...',
        }
      }
    }
  ]
}


Action fields

Required fields

FieldTypeNotes
actionTypeActionTypeRequired. The action that the user wants to perform. See action types below for a list of action types
contentIdstringRequired. The content ID for this action. If this is an action with a shopping cart (CHECKOUT, PURCHASE) with multiple items, it is okay to leave blank and fill in cart.items.item_id. The content_id is used as a hint when the impression_id is not set. For more accurate results, set impression_id if available. The content_id is also useful for debugging
userInfocommon.UserInfoRequired. Must be set on LogRequest or here

Optional fields

The most commonly used optional fields include cart, customActionType, impressionId, name, properties, and timing.

FieldTypeNotes
actionIdstringPrimary key. SDKs usually handle this automatically. For details, see https://github.com/promotedai/schema#setting-primary-keys
autoViewIdstring
cartCartThe shopping cart
clientInfocommon.ClientInfoIf not set, it is set by API servers using LogRequest.client_info
clientPositionIndexPathPosition the action within its enclosing list
customActionTypestringThis field must be set when actionType: CUSTOM_ACTION_TYPE
devicecommon.DeviceUsed for debugging in early stages of integration
elementIdstring
hasSuperimposedViewsboolIndicates that this action occurred in a view that may not be topmost in the view hierarchy
idProvenancesIdentifierProvenancesUsed for debugging
impressionIdstringSee content_id for details
insertionIdstring
namestringCustom, human-readable name of the action that the user performed, used for debugging (e.g., "product clicked"). Do not put personally identifiable information.
navigateActionNavigateAction
platformIduint64Do not set. Will be set by API servers using LogRequest.platform_id
propertiescommon.PropertiesCustom properties of the platform
requestIdstring
sessionIdstring
timingcommon.TimingMust use a long epoch milliseconds (e.g., 1723760094). If not set, it is set by API servers using LogRequest.timing
viewIdstring

Sending purchase and other standards events

Here's an example for logging a purchase to Promoted. The LogRequest message supports batch logging records.

# Some fields like `timing`, `insertionId`, `impressionId`, `properties` and `cart` are optional on Action records.
# The user_info can be set within each record, like `action`, or in the top-level LogRequest
echo '{
  "userInfo": {  
    "anonUserId": "0ea9657c-bd64-4709-9cc0-fbbcdd8d9f43",
    "userId": "user1"
  },  
  "action": [  
    {  
      "actionId": "b59b77c7-a55a-4f01-91b5-58a3d4e36876",  
      "timing": {
        "clientLogTimestamp": 1641038400000
      },
      "actionType": "PURCHASE",
      "insertionId": "b59b77c7-a55a-4f01-91b5-58a3d4e36876",
      "contentId": "123",
      "impressionId": "cb97da40-1c56-45fc-b8c5-c525c384ae48",
      "properties": {
        "struct": {
          "customKey1": "customValue",
          "customKey2": 3
        }
      },
      "cart": {
        "contents": [
          {
            "contentId": "abc",
            "quantity": 1,
            "pricePerUnit": {
              "currencyCode": "USD",
              "amountMicros":  10000000
            }
          }
        ]
      }
    }
  ]  
}' > /tmp/action.json

curl -H "Content-Type: application/json" \
    -H "x-api-key: yourapikey" --data "@/tmp/action.json" http://www.promoted.ai/log

In this example:

  • anonUserId is the anonymous user ID that matches the other log records. Usually, this needs to be plumbed through more code paths.
  • amountMicros is the currency amount (e.g. $s) multiplied by 1 million. This lets us keep money values as longs.

Sending post-purchase events with custom properties

Post-purchase events like cancelations can use the REFUND_PURCHASE action type, or CUSTOM_ACTION_TYPE for events that are not represented already. For example, a food delivery platform may have custom actions to represent a completed delivery, modifications to the order, or a completed review. This would be represented as a CUSTOM_ACTION_TYPE, with the Action.custom_action_type field set to custom strings, such as ORDER_COMPLETE.

📘

Using custom action types

If using a unique action type not otherwise represented in action, you should set both actionType and customActionType.

{
  action: [
    {
      actionType: 'CUSTOM_ACTION_TYPE',
      customActionType: '...' // your custom action type name
      ... // other fields
    }
  ]
}

These are sent in the same way as other server-side metrics API calls.

// Switching to Typescript to support inline comments.
const logRequest = {  
  userInfo: {  
    anonUserId: "0ea9657c-bd64-4709-9cc0-fbbcdd8d9f43",
    userId: "user1"
  },  
  action: [  
    {  
      actionId: "b59b77c7-a55a-4f01-91b5-58a3d4e36876",
      actionType: "CUSTOM_ACTION_TYPE",
      customActionType: "MODIFY_ORDER",
      contentId: "123",
      properties: {
        struct: {
          // Let Promoted know if you have sensitive fields custom properties. 
          orderId: "abc",
          // Can log the delta to an order.
          orderDelta: [
            {
              "contentId": "abc",
              "quantity": -2,
              "pricePerUnit": {
                "currencyCode": "USD",
                "amountMicros":  10000000
              }
            }
          ],
          // Can also log the current order state.
          currentOrder: [
            {
              "contentId": "abc",
              "quantity": 1,
              "pricePerUnit": {
                "currencyCode": "USD",
                "amountMicros":  10000000
              }
            },
            {
              "contentId": "def",
              "quantity": 2,
              "pricePerUnit": {
                "currencyCode": "USD",
                "amountMicros":  10000000
              }
            }
          ]
        }
      }
    }
  ]  
};

Sending impressions

This might happen if you have your own impression records and want to log them from your server instead of using Promoted's Snowplow-compatible path.

# insertionId is optional.  It improves joining.
echo '{
  "userInfo": {  
    "anonUserId": "0ea9657c-bd64-4709-9cc0-fbbcdd8d9f43",
    "userId": "user1"
  },
  "impression": [  
    {  
      "impressionId": "cb97da40-1c56-45fc-b8c5-c525c384ae48",
      "timing": {
        "clientLogTimestamp": 1641038400000
      },
      "insertionId": "b59b77c7-a55a-4f01-91b5-58a3d4e36876",
      "contentId": "123"
    }
  ]  
}' > /tmp/impression.json

curl -H "Content-Type: application/json" \
    -H "x-api-key: yourapikey" --data "@/tmp/impression.json" http://www.promoted.ai/log 

Impression fields

All fields are optional. See our schema on Github for more details.

FieldTypeDescription
autoViewIdstring
clientInfocommon.ClientInfoIf not set, API server uses LogRequest.client_info.
clientPositionIndexPathPosition the impression within its enclosing list.
contentIdstringcontent_id is used as a hint when insertion_id is not set. For more accurate results, set insertion_id.
hasSuperimposedViewsboolIndicates that this impression occurred in a view that may not be topmost in the view hierarchy, and thus may have been obscured from the user.
idProvenancesIdentifierProvenancesUsed for debugging.
impressionIdstringPrimary key. SDKs usually handle this automatically. For details, see setting-primary-keys.
insertionIdstring
platformIduint64Do not set. Will be set by API servers using LogRequest.platform_id.
propertiescommon.PropertiesCustom properties per platform.
requestIdstring
sessionIdstring
sourceTypeImpressionSourceType
timingcommon.TimingIf not set, set by API servers. If not set, API server uses LogRequest.timing.
userInfocommon.UserInfoMust be set on LogRequest or here.
viewIdstring


Action types

These action types are supported in the action_type field. See our schema on Github for more details.

ActionDescription
ADD_TO_CARTAdd an item to shopping cart
ADD_TO_LIST(Wish)list content
ANSWER_QUESTIONAnswer a question about content
ASK_QUESTIONAsk a question about content
BOOKMARKBookmark content
CANCEL_PURCHASEUser-generated cancel before the purchase is completed. Negates a PURCHASE event
CHECKOUTStart the checkout flow
COMPLETE_SIGN_INComplete sign-in. No content_id needed. If set, set it to the Content's ID (not User)
COMPLETE_SIGN_UPComplete sign-up. No content_id needed. If set, set it to the Content's ID (not User)
COMMENTComment on content
MAKE_OFFERMake an offer on content
LIKELike content
NAVIGATENavigate to details about content
ONGOING_PURCHASEA delayed purchase related to a previous purchase, such as a subscription, delayed add-ons
PURCHASEPurchase an item. Might not result in a completed order
REFUND_PURCHASERefund a purchase after completion. Can be used separately from CANCEL_PURCHASE to indicate that revenue was already realized.
REMOVE_BOOKMARKRemove bookmark from content
REMOVE_FROM_CARTRemove an item from the shopping cart
REMOVE_FROM_LISTRemove content from (wish)list
SELECT_CONTENTThis is an internal, synthetic event that indicates an item was selected. It can be used to model multiple events as a click, e.g.,union(NAVIGATE, BOOKMARK, LIKE, ADD_TO_CART). For details on use, discuss with Promoted.
SHAREShare content
UNFOLLOWUnfollow a followed seller or creator
UNLIKEUn-like content

What’s Next