Why using a webhook?
From your Fastory account, you can send the data collected by your contests towards the URL of your choice.
You need to create this URL in the first place.
Then, you'll be able to send the data towards your servers or web service.
In which cases can I use a webhook?
- You need to treat data on your end in order to record scores on your server, synchronize data, login users...
- You need to trigger a script after specific bot questions (for example sending emails) or Zapier
Add-on activation
Follow these steps:
- From your workspace, go to the
add-ons
page
- Click on the search bar and type
webhook
Webhook settings
Once the add-on is activated:
- Go to
Experience
in your workspace
- Go to
Integrations
- Click on the button
Create integration
A window appears with the setting options:
Configuration
- Integration Title: Assign a distinctive title for easier webhook management.
- Endpoint (URL): Specify the target URL for the integration.
- Token (optional): Enter the token if required for authentication or other processes.
- Once these settings are in place, click on
Test connection
to initiate a test payload to the endpoint and validate the connection.
{ "createdAt": "0000-00-00T00:00:00.000Z", "workspaceId": "1", "visitorId": "123", "story": { "id": "xxxxxxxx", "name": "webhooks" }, "type": "chatbot", "chatbot": { "answers": [ { "id": "xxxxxxxx", "value": "Answering this", "label":null } ], "question": { "id": "4321", "value": "What is your email ?", "attribute": "email", "type": "text" } } }
Target
You can now select a target:
- bot: Receive responses generated by a bot following a predefined question.
- story_bot: In addition to the bot's responses, also retrieve URL parameters and game participations from the story following a predefined question.
- workspace: Set up global settings for your workspace. At present, this only allows you to determine after which optin the data will be sent.
Payloads
There are three different payloads:
- games: Encompasses all participations in various games such as runner, basketball, football, quiz, and others.
- chatbot: Covers all responses to questions posed by the bot, including opt-ins.
- contest: Includes all participations in contests, whether they're of the "instant win" type or "draw".
Games Payload
List of game types:
- basketGame
- runnerGame
- footballGame
- quizGame
- calendarQuizGame
- swipeQuizGame
- memoryGame
- swipePollGame
- swipeMusicQuizGame
- selfieGame
{ "createdAt": "0000-00-00T00:00:00.000Z", "visitorId": "xxxxxxxx", "story": { "id": "xxxxxxxx", "name": "My story's name", }, "type": "games", "games": { "type": "basketGame", "score": 0, "timeLeft": 0.0, "createdAt": "0000-00-00T00:00:00.000Z", "brick": { "id": "xxxxxxxx", "label": "Basket1" } } }
Selfie Game
For games of the Selfie type, we have added participation as well as vote-type participations. Example of feedback when participating:
Example of feedback when voting:
⚠️ For participations when a player votes, id
corresponds to the ID of the vote, and vote
corresponds to the ID of the participation for which the user voted.
Chatbot Payload
Here's the payload sent following the answer to an email
type question:
{ "createdAt": "0000-00-00T00:00:00.000Z", // Payload creation date "workspaceId": "xxxxxxxx", // Fastory's workspaceID "visitorId": "xxxxxxxx", // Fastory's VisitorID "story": { "id": "xxxxxxxx", // Story's ID "name": "My story's name", // Story's name }, "type": "chatbot", // Payload type "chatbot": { "answers": [ // An Array of objects that contains all answers to the question. Most of the time, this Array will have length of 1. For optins questions, the Array will have length of the number of propositions. { "value": "An answer", // String | Boolean | Number "label":null, // If the question is an optin, the label will have a value, null otherwise "id": "00000000-0000-0000-0000-000000000000" // Only exists if the question is an optin, this is the optin ID } ], "question": { // An object with all questions details "id": "xxxxxxxx", // Question ID "value": "Now your email please", // The question value "attribute": "email", // The attribute "type": "text" // The question type } } } J
Now, here's the payload sent in response to an optin
type question:
{ "createdAt": "0000-00-00T00:00:00.000Z", // Payload creation date "workspaceId": "xxxxxxxx", // Fastory's workspaceID "visitorId": "xxxxxxxx", // Fastory's VisitorID "story": { "id": "xxxxxxxx", // Story's ID "name": "My story's name", // Story's name }, "type": "chatbot", // Payload type "chatbot": { "question": { "id": "xxxxxxxx", // Question ID "value": "Please answer to these optins", // The question asked "type": "optins" // Question Type (here optins) }, "answers": [ { "id": "00000000-0000-000x-x000-xx000x0x00xx", // Optin's ID "label": "Optin 1", // Optin's name "value":true // Here the visitor checked this answer }, { "id": "00000000-0000-000x-x000-xx000x0x0xxx", "label": "Optin 2", "value":true }, { "id": "00000000-0000-000x-x000-xx000x0xxxxx", "label": "Optin 3", "value":false } ] } }
All of a user's information is sent at once. This can result in a rather large payload:
{visitorId: 'xxxxxxxx', workspaceId: 'xxxxxxxx', story: { id: 'xxxxxxxx', name: '11Mai2021', customId: null }, optins: { optin_allo: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'allo', value: true, }, optin_first_name: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'first_name', value: false, }, optin_Chocolat: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'Chocolat', value: true, }, optin_city: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'city', value: true, }, }, chatbot: { message_dTyNCd8M: { answers: { answer_0: { value: 'xxxxxxxx.com', label: null } }, question: { id: 'xxxxxxxx', value: 'Quel est votre email?', attribute: 'email', type: 'text', }, }, message_RBhT5iev: { answers: { answer_0: { value: 'Excellent', label: null } }, question: { id: 'xxxxxxxx', value: 'Bonjour ! Comment allez-vous ?', attribute: 'single_choice', type: 'text', }, }, message_smZ2Fmej: { question: { id: 'xxxxxxxx', value: 'Optin First Name', type: 'optins' }, answers: { answer_0: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'allo', value: true, }, answer_1: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'first_name', value: false, }, answer_2: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'Chocolat', value: true, }, }, }, message_67eSfsv5: { question: { id: 'xxxxxxxx', value: 'City optin', type: 'optins' }, answers: { answer_0: { id: '00000000-0000-000x-x000-xx000x0xxxxx', label: 'city', value: true, }, }, }, }, "visitor": { "email": "john@doe.com", "date_of_birth": "2021-04-30", "single_choice": "Excellent", "phone": "+33600000000", "first_name": "John", "last_name": "Doe", "media": "https://static.fastory.io/uploads/account_id/some_upload_id.jpeg", "multiple_choice": "3, 2", "terms_conditions": "Accept", "rating": "2" }, "games": [ { "type": "memoryGame", "score": 5, "timeLeft": 39.70499999999995, "createdAt": "2021-04-19T13:31:06.418Z", "brick": { "id": "xxxxxxxx", "label": "Memory" } }, { "type": "swipeQuizGame", "score": 70, "createdAt": "2021-04-19T13:30:34.885Z", "brick": { "id": "xxxxxxxx", "label": "Swipe Quiz" } }, { "type": "runnerGame", "score": 55, "timeLeft": 2992.486000000009, "createdAt": "2021-04-19T13:29:26.621Z", "brick": { "id": "xxxxxxxx", "label": "Runner" } }, { "type": "basketGame", "score": 5, "timeLeft": 2.7430000000002246, "createdAt": "2021-04-19T13:29:06.330Z", "brick": { "id": "xxxxxxxx", "label": "Basket1" } }, { "type": "footballGame", "score": 4, "timeLeft": -2.0083333333331868, "createdAt": "2021-04-19T13:30:08.915Z", "brick": { "id": "xxxxxxxx", "label": "Football" } } ], "contests": [ { "type": "sweepstake", "id": "00000000-0000-000x-x000-xx000x0xxxxx", "label": "Tirage au sort", "status": "live", "result": "OPERATOR_PARTICIPATION_ALREADY_SIGNED_UP", "reward":null }, { "type": "instant_win", "id": "00000000-0000-000x-x000-xx000x0xxxxx", "label": "Instant Win", "status": "ready", "result": "already lose", "reward":null } ] }
Given the length of this payload, here's a typing table that might help you better understand its structure:
OptinsObject { [key: string]: { "id"?: ID; "label": string; "value": string | boolean; } } AnswerObject { [key: string]: { "value": string; "label":null | string; "id"?: UUID; } } QuestionObject { "id": ID; "value": string; "attribute": string; "type": string; } ChatbotObject { [key: string]: { "answers": AnswerObject; "question": QuestionObject; } } BrickObject { "id": ID; "label": string; } GamesObject { "type": string; "score": number; "timeLeft": float; "createdAt": Date; "brick": BrickObject; } RewardObject { "id": UUID; "label": string; } ContestsObject { "type": string; "id": UUID; "label": string; "status": "live" | "closed"; "result": string; "reward": RewardObject } StoryObject { "id": string; "name": string; } { "visitorId": string; "workspaceId": string; "story": StoryObject; "optins": OptinsObject; // Warning: Optins which was an array of optins is now an object containing all the optins (since June 15, 2022) "chatbot": ChatbotObject; // Warning: Chatbot which was an array of optins is now an object containing all the chatbot (since June 15, 2022) "visitor": { [attributeName: string]: string; }, "games": Array<GamesObject>; "contests": Array<ContestObject>; }