Send Profile Event

POSThttps://app.botsi.com/api/v1/web-api/events

After the paywall has been shown to the user, call Send Profile Events to track the paywall impression. This data is used for analytics and to optimize paywall selection over time.

This request should be triggered from the app, immediately after the paywall is displayed.

Paywall impressions are counted uniquely per user. If the same paywall impression event is sent multiple times for the same user, it will be counted only once.

Follow the notes below for a successful request:
  • The request body must be an array of event objects. For tracking a paywall view, send a single event in the array.

  • You must identify the user by providing either profileId or customerUserId.

  • Echo the paywallSessionId returned by Get Paywall. Botsi fills in the attribution fields from its own record of the decision.

Attribution comes from the paywall session token

Every Get Paywall response includes a paywallSessionId. Send it back here and Botsi supplies paywallId, placementId, abTestId, aiPricingModelId and isExperiment itself, from the decision it recorded when it served the paywall.

This exists because the older approach made you responsible for the accuracy of your own experiment results: the four fields were reassembled by hand on the client, and a value that disagreed with Botsi's record was accepted as sent. Echoing one opaque string removes that step.

Request Body

application/json (array of objects)

ParameterTypeRequiredDescription
eventTypestringRequiredType of event. Example: paywall_shown
paywallSessionIdstringRecommendedOpaque token from the Get Paywall response (data.paywallSessionId). Supplies paywallId, placementId, abTestId, aiPricingModelId and isExperiment.
profileIdstringOptionalBotsi profile ID returned by Create Profile. Provide either profileId or customerUserId
customerUserIdstringRecommendedYour internal user ID. Provide either profileId or customerUserId
paywallIdintegerRequired unless paywallSessionIdFrom Get Paywall response (data.id). Supplied by paywallSessionId when that is present.
placementIdstringRequired unless paywallSessionIdSame placement ID used to fetch the paywall. Supplied by paywallSessionId when that is present.
isExperimentbooleanRequired unless paywallSessionIdWhether the paywall came from the AI Pricing model. Supplied by paywallSessionId when that is present.
aiPricingModelIdintegerRequired unless paywallSessionIdThe AI Pricing model that served the paywall. Supplied by paywallSessionId when that is present.

Example Request

With the token, a paywall view is two fields plus the user identifier. This is the complete event.

[
  {
    "profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
    "eventType": "paywall_shown",
    "paywallSessionId": "v1.eyJhIjo0MDIxLCJ3Ijo5MDUsInAiOiJvbmJvYXJkaW5nIiwiaSI6MTc4NTMxMjAwMH0.QmzR1w"
  }
]

Working With the Token

  • Treat it as opaque. Store and return it byte for byte. Do not parse, decode, truncate, or construct it. The internals are an implementation detail and will change. It is signed, so an edited token is rejected rather than misattributed. It starts with a version prefix; do not depend on that either.

  • Size. Roughly 200 characters today, with no fixed maximum. Do not use a narrow column — TEXT or VARCHAR(512) is a safe choice.

  • One token per paywall fetch. Store it against the user, alongside whatever you already store.

  • Views expire, transactions do not. A paywall_shown event is accepted for 24 hours after the fetch that minted the token. Every other event type, and all transactions, accept a token of any age. Echoing a three-year-old token on today's renewal is correct and expected.

  • The token wins. If a request carries both a token and explicit fields that disagree with it, Botsi persists the token's values.

  • A broken token fails the request. Unknown or stale abTestId values are still accepted as before, but a paywallSessionId that fails its signature check, or that was issued for a different app, returns 400 and nothing is stored. That means the value was corrupted or forged, not merely out of date.

  • Sending no token is still valid. Existing integrations are unaffected.

cURL Example

curl -X POST "https://app.botsi.com/api/v1/web-api/events"      -H "Authorization: {{secret_key}}"      -H "Content-Type: application/json"      -d '[
       {
         "profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63",
         "eventType": "paywall_shown",
         "paywallSessionId": "v1.eyJhIjo0MDIxLCJ3Ijo5MDUsInAiOiJvbmJvYXJkaW5nIiwiaSI6MTc4NTMxMjAwMH0.QmzR1w"
       }
     ]'

Errors

A rejected paywallSessionId returns 400 with a message in the body, and nothing is stored.

MessageCause
paywallSessionId is not a valid Botsi paywall session token.Malformed, truncated, or the signature does not verify
paywallSessionId was issued for a different app.Token belongs to another app's secret key
paywallSessionId uses an unsupported token version.Version prefix Botsi does not recognise
paywallSessionId has expired for this event type. Fetch a new paywall before reporting the view.paywall_shown sent outside the 24-hour view window

Response

200Event tracked

A successful request will return a confirmation response.

{
  "ok": true
}

Deprecated: sending attribution fields directly

Deprecated This is the original form of the request, and it still works. Nothing is being removed and there is no migration deadline. If your integration already sends these fields, it will keep working unchanged.

Instead of paywallSessionId, send the attribution fields you stored from the Get Paywall response. In this form paywallId, placementId, isExperiment and aiPricingModelId are all required, and each must carry the value Botsi returned for that paywall fetch.

[
  {
    "eventType": "paywall_shown",
    "paywallId": 42,
    "placementId": "ai-placement-id",
    "isExperiment": true,
    "aiPricingModelId": 32,
    "profileId": "0072102a-c00c-4ea5-9271-1b6e975f2d63"
  }
]

Botsi accepts these values as sent. A value that disagrees with the decision Botsi recorded is not flagged, so it reaches experiment results and AI Pricing training data as-is. That is the reason paywallSessionId is recommended for new integrations — not that these fields are unreliable, but that keeping them correct is work the token does for you.

Try It Out

https://app.botsi.com/api/v1/web-api
Response
Click "Send API Request" to see the response here.