Form Studio
date: "2023-09-05" Author: "Sinisa Jovic" Page: "Solver AI Studio Form Studio API Reference" hide: - toc - path
Intro Steps
The first step to integrate your first form using SAIS API is to access the API documentation on the link: Form Studio API and it looks something like this:
Header parameters
Name | Value | Description |
---|---|---|
Authorization required |
Bearer |
Token is retriveing called Auth API |
Content Type required |
application/json |
Method GET: /forms-studio/forms
{
"offset": 0,
"limit": 10,
"count": 100,
"forms": [
{
"form_id": "subscription-form-11331234asdaw",
"form_name": "Subscription form",
"form_title": "Subscribe to newsletter",
"form_type": "embedded",
"form_description": "This form is used for collecting new subscribers",
"date_created": "2021-10-01T10:12:09",
"date_modified": "2021-10-01T12:30:15",
"segment_size": 34678,
"client_name": "web-seller",
"author": "John Doe",
"form_template_id": "template-form-11331234asdaw",
"form_integration": "<form id=\"myForm\" action=\"/action_page.php\"> <label for=\"first_name\">First name:</label><br><input type=\"text\" id=\"first_name\" name=\"first_name\" value=\"John\"><br><label for=\"email\">Email:</label><br><input type=\"text\" id=\"email\" name=\"email\" value=\"john@example.com\"><br><br><input type=\"submit\" value=\"Submit\"></form><script>function myFunction(){document.getElementById(\"myForm\").submit()}</script>"
}
]
}
After that, you need to identify your Client Name which can be collected from your subdomain and is usually correlated to your company domain. For example, in this link, dev is Client Name https://dev.thingsolver.com/portal/ and you will need to remember it for future API calls but you will also need a full base link to be able to perform API calls.
Authenticate In the further examples I will be using https://dev.thingsolver.com/ as my base URL and the next logical step is to authenticate myself by calling the Auth API – Login endpoint like this:
Method POST: https://dev.thingsolver.com/api/latest/auth/login
{
"username": "<enter-your-account-email>",
"password": "<enter-your-account-password>"
}
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiTVBNVmw5WllDR3hsNUdkZDlWZDBMc201WVA1Z19HeFRtVkZadGhnR3FNIn0.eyJleHAiOjE2OTIzMTE1MDMsImlhdCI6MTY5MjI4MjcwMywianRpIjoiOGVhOGEzMzItYTQwZS00ZDBhLTgwZjktZTJlZjYxYjMwYmEyIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrLWh0dHAuZGVmYXVsdC9hdXRoL3JlYWxtcy9kZXYiLCJzdWIiOiJmN2Q5YzRjOC03ZGQ3LTQzYzctYmU0Yi1iYTQwYzQ2Mjc1YjUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJkZXYiLCJzZXNzaW9uX3N0YXRlIjoiYWVjMWI4ZjctNTFlZC00MDMzLWFiZDMtNjE5ODRhNmQyMjg2IiwiYWNyIjoiMSIsInNjb3BlIjoiZGV2Iiwic2lkIjoiYWVjMWI4ZjctNTFlZC00MDMzLWFiZDMtNjE5ODRhNmQyMjg2IiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1kZXYiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sImdyb3VwcyI6WyJzdXBlci11c2VyIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImR1c2FuQHRoaW5nc29sdmVyLmNvbSIsImdpdmVuX25hbWUiOiJEdXNhbiIsImZhbWlseV9uYW1lIjoiTWlqYXRvdmljIiwiZW1haWwiOiJkdXNhbkB0aGluZ3NvbHZlci5jb20ifQ.gRUxyKAb8QZgHoTwpCHGzJ7GyDwfMmhzXatsptkrHaAOHMaEkRdzFrP-odeSOQob1kSTUT2vS6eYri22zD8nkFNgxFosvYUGfnVXVS_RPmHwT4JiJOHq2XFumpldA6fZ2uMtRGuHrhCZaDUO1_l0as5y4tf62GhmtyttoVj8g23rOH0n6lbPbFdEt2pF7MBRAhpQdXMKJAcJi-KlUwMkAjmp_VcpkAqsACTaYxast8MsOEiUg9-EskVtn-Mircv4pd7rn7s9VvWg9N1AUXGctKC0v05_fkciMkieArxfNHR2o3tPl9kJnkznSc_LJ7GUHbwvOrvdT3sXoAz946vESA",
"expires_in": "28800",
"refresh_expires_in": "604800",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMTljYTFjYS0wMmFjLTQxMzMtYTljZC0xNWJlYmJmZjA4OTAifQ.eyJleHAiOjE2OTI4ODc1MDMsImlhdCI6MTY5MjI4MjcwMywianRpIjoiNGQzMWI4OWQtYzU4NC00NjVjLThlZDMtNTFmMmYxMTkzNTk5IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrLWh0dHAuZGVmYXVsdC9hdXRoL3JlYWxtcy9kZXYiLCJhdWQiOiJodHRwOi8va2V5Y2xvYWstaHR0cC5kZWZhdWx0L2F1dGgvcmVhbG1zL2RldiIsInN1YiI6ImY3ZDljNGM4LTdkZDctNDNjNy1iZTRiLWJhNDBjNDYyNzViNSIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJkZXYiLCJzZXNzaW9uX3N0YXRlIjoiYWVjMWI4ZjctNTFlZC00MDMzLWFiZDMtNjE5ODRhNmQyMjg2Iiwic2NvcGUiOiJkZXYiLCJzaWQiOiJhZWMxYjhmNy01MWVkLTQwMzMtYWJkMy02MTk4NGE2ZDIyODYifQ.XFjKqM6muCnDHVc3Ut6kbmUmxZCzjWS1U6BaCs5RxEs",
"token_type": "Bearer",
"not_before_policy": "0",
"session_state": "aec1b8f7-51ed-4033-abd3-61984a6d2286",
"scope": "dev"
}
Take the access_token from the response and add it to every request from now on as a new header value:
Choose or create a template
In Forms Studio, there is a main component called a template that is used to define all the form fields, labels, names, and placeholders that can be reused in several form instances. Create separate forms for separate websites using the same template.
You can see the list of templates by calling the endpoint:
Method GET: https://{client}.thingsolver.com/api/latest/forms-studio/templates
And response will return a list of all forms. We will display only one in this example but we give you several options out of the box.
{
"offset": 0,
"limit": 1,
"templates": [
{
"form_template_name": "Register",
"author": "default",
"is_predefined": true,
"fields": [
{
"field_label": "Enter your email ",
"field_name": "enter_your_email_",
"field_placeholder": "",
"field_type": "email",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "Enter your first name",
"field_name": "enter_your_first_name",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "Enter your last name",
"field_name": "enter_your_last_name",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": false,
"field_options": []
},
{
"field_label": "Enter your country",
"field_name": "enter_your_country",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": false,
"field_options": []
},
{
"field_label": "Enter your city",
"field_name": "enter_your_city",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": false,
"field_options": []
},
{
"field_label": "Enter your birthday ",
"field_name": "enter_your_birthday_",
"field_placeholder": "DD / MM / YYYY",
"field_type": "date",
"css_class": [],
"is_required": false,
"field_options": []
},
{
"field_label": "REGISTER NOW",
"field_name": "submit",
"field_placeholder": "",
"field_type": "submit",
"css_class": [],
"is_required": true,
"field_options": []
}
],
"submit_success": {
"message": "Form submitted successfully!",
"css_class": []
},
"submit_failed": {
"message": "Form submission failed!",
"css_class": []
},
"form_template_id": "form-template-id-462a7407999f40cf8abebda8ff79bdbf",
"date_created": "2023-07-14T11:39:34",
"date_modified": "2023-07-14T11:39:34"
}
],
"count": 4
}
You can use this same request body to create your own template or modify it to your needs by calling the request:
POST: https://dev.thingsolver.com/api/latest/forms-studio/templates
{
"form_template_name": "Register Custom Form",
"author": "default",
"is_predefined": false,
"fields": [
{
"field_label": "Enter your email",
"field_name": "enter_your_email",
"field_placeholder": "",
"field_type": "email",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "Enter your first name",
"field_name": "enter_your_first_name",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "REGISTER NOW",
"field_name": "submit",
"field_placeholder": "",
"field_type": "submit",
"css_class": [],
"is_required": true,
"field_options": []
}
],
"submit_success": {
"message": "Form submitted successfully!",
"css_class": []
},
"submit_failed": {
"message": "Form submission failed!",
"css_class": []
}
}
And you will get the response with the similar body but with one important key that is called form_template_id you will need it to create your form with this template:
{
"form_template_name": "Register Custom Form",
"author": "default",
"is_predefined": false,
"fields": [
{
"field_label": "Enter your email ",
"field_name": "enter_your_email_",
"field_placeholder": "",
"field_type": "email",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "Enter your first name",
"field_name": "enter_your_first_name",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "REGISTER NOW",
"field_name": "submit",
"field_placeholder": "",
"field_type": "submit",
"css_class": [],
"is_required": true,
"field_options": []
}
],
"submit_success": {
"message": "Form submitted successfully!",
"css_class": []
},
"submit_failed": {
"message": "Form submission failed!",
"css_class": []
},
"form_template_id": "form-template-id-c57fac4140c941f59ac2e172ff9dcfad",
"date_created": "2024-10-17T14:56:49",
"date_modified": "2024-10-17T14:56:49"
}
And now we will create a new form using this template.
Method POST: https://dev.thingsolver.com/api/latest/forms-studio/forms
{ "form_name": "My CS register", "form_title": "Hi, please register for newsletter", "form_type": "embedded", "form_template_id": "form-template-id-c57fac4140c941f59ac2e172ff9dcfad", "form_description": "This is custom registration form used on my special website", "author": "Dusan", "client_name": "dev" }
{
"form_name": "My CS register",
"form_title": "Hi, please register for newsletter",
"form_type": "embedded",
"form_template_id": "form-template-id-c57fac4140c941f59ac2e172ff9dcfad",
"form_description": "This is custom registration form used on my special website",
"author": "Dusan",
"client_name": "dev"
}
As you can see we have received the client name when creating this form which is our Client Name which is equal to the value form our subdomain and our template id is the one we have created previously.
Now we have created our first form which will return the following response:
{
"form_name": "My CS register",
"form_title": "Hi, please register for newsletter",
"client_name": "dev",
"form_type": "embedded",
"form_description": "This is custom registration form used on my special website",
"form_template_id": "form-template-id-c57fac4140c941f59ac2e172ff9dcfad",
"author": "Dusan",
"form_id": "form-id-9face8d6f9254401a5d689873988a406",
"date_created": "2023-08-17T15:08:46",
"date_modified": "2023-08-17T15:08:46",
"segment_size": 0,
"form_integration": "<style> .suite-form-inputs { width: 100%; padding: 12px 20px; margin: 8px 0; display: inline-block; background: #ffffff; border: 1px solid #eeeeee; box-shadow: 0px 4px 7px -5px rgba(0, 0, 0, 0.14); border-radius: 4px; box-sizing: border-box; } .suite-submit { width: 100%; height: 60px; background-color: #ededed; color: #191f3e; padding: 14px 20px; margin: 8px 0; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 16px; } .suite-form-labels, .suite-success-message, .suite-error-message { font-family: sans-serif; font-style: normal; font-weight: 400; font-size: 14px; line-height: 16px; color: #191f3e; } .suite-success-message { color: #238738; text-align: center; } .suite-error-message { color: #b9240a; text-align: center; } .suite-form-title { font-family: sans-serif; font-style: normal; font-weight: 400; font-size: 20px; line-height: 23px; color: #191f3e; padding-bottom: 15px; border-bottom: 1px solid #dddddd; } .suite-form-desc { font-family: sans-serif; font-style: normal; font-weight: 400; font-size: 16px; line-height: 19px; color: #666666; padding-bottom: 15px; border-bottom: 1px solid #dddddd; } </style><h1 class=\"suite-form-title\">Hi, please register for newsletter</h1><p class=\"suite-form-desc\">This is custom registration form used on my special website</p><form id=\"form-id-9face8d6f9254401a5d689873988a406\"><label class=\"suite-form-labels\">Enter your email </label><br /><input type=\"email\" class=\"suite-form-inputs\" required=\"required\" placeholder=\"\" name=\"enter_your_email_\" /><br /><label class=\"suite-form-labels\">Enter your first name</label><br /><input type=\"text\" class=\"suite-form-inputs\" required=\"required\" placeholder=\"\" name=\"enter_your_first_name\" /><br /><br /><input type=\"submit\" value=\"REGISTER NOW\" class=\"suite-submit\" /><p id=\"success-message\" class=\"suite-success-message\">Form submitted successfully!</p><p id=\"error-message\" class=\"suite-error-message\">Form submission failed!</p></form><script> const requiredCheckboxes = document.querySelectorAll('input[type=\"checkbox\"][required]'); requiredCheckboxes.forEach((el) => { el.setCustomValidity('Please select one of these options.'); el.addEventListener('change', (e) => { const checkboxGroup = Array.from(requiredCheckboxes).filter((x) => x.name === e.srcElement.name); if (checkboxGroup.some((checkbox) => checkbox.checked)) { document.querySelectorAll('input[name=' + e.srcElement.name + ']').forEach((reqElement) => { reqElement.required = false; reqElement.setCustomValidity(''); }); } else { el.setCustomValidity('Please select one of these options.'); } }); }); const getCheckedValues = () => { return Array.from(document.querySelectorAll('input[type=\"checkbox\"]')) .filter((checkbox) => checkbox.checked) .reduce((acc, value) => { if (acc.hasOwnProperty(value.name)) { acc[value.name].push(value.value); } else { acc[value.name] = [value.value]; } return acc; }, {}); }; const checkMessageStatus = (statusMessage) => { const successMessage = document.getElementById('success-message'); const errorMessage = document.getElementById('error-message'); switch (statusMessage) { case 'success': successMessage.style.display = 'block'; errorMessage.style.display = 'none'; break; case 'error': successMessage.style.display = 'none'; errorMessage.style.display = 'block'; break; default: successMessage.style.display = 'none'; errorMessage.style.display = 'none'; break; } }; checkMessageStatus(''); const getData = (form) => { const collectFormData = { client_name: 'dev', fields: { ...Object.fromEntries(new FormData(form)), ...getCheckedValues() } }; const form_id = document.querySelector('form').id; const headers = { 'Content-Type': 'application/json' }; fetch(`https://dev-forms.thingsolver.com/api/latest/forms-studio/collect/${form_id}`, { method: 'POST', headers: headers, body: JSON.stringify(collectFormData) }) .then((response) => response.json()) .then((data) => checkMessageStatus('success')) .catch((error) => checkMessageStatus('error')); }; document.querySelector('form').addEventListener('submit', (e) => { e.preventDefault(); getData(e.target); }); </script>"
}
One more important thing is that new form_id is generated, not to confuse it with form_template_id which is a separate thing that we used previously. We will need the form_id if we want to send the data using API instead of generated HTML in one of the next sections
Integrating the Data
When form creation is finished we can use the generated HTML code form response and embed it to our website which will automatically send the data to your SAIS environment.
Open HTML in local browser and submit filled form. That will sent the data to your SAIS environment and in a few minutes, records will be available in segment. Form count will be update incrementally with records collection.
Form HTML is a bare bone and optionally, you can apply additionally CSS code to match your design.
Create your own Form
If you want to create your own HTML and JS code for the form and only use our API to collect everything, you can do that the following way:
Method POST: https://forms.thingsolver.com/api/latest/forms-studio/collect/form-id-9face8d6f9254401a5d689873988a406
{
"client_name": "dev",
"fields": {
"enter_your_email_": "dusan@thingsolver.com",
"enter_your_first_name": "Dusan"
}
}
Take a look at this request, it sends the data to the unify collection system and it will osr everything by your client_name and form_id. The different thing of this API is its subdomain which is forms instead of client_name and at the end of this URL, we add the value of form_id previously mentioned. The body is formed from your template field_names that are not of type submit.
{
"field_label": "Enter your email ",
"field_name": "enter_your_email",
"field_placeholder": "",
"field_type": "email",
"css_class": [],
"is_required": true,
"field_options": []
},
{
"field_label": "Enter your first name",
"field_name": "enter_your_first_name",
"field_placeholder": "",
"field_type": "text",
"css_class": [],
"is_required": true,
"field_options": []
}
{
"client_name": "dev",
"fields": {
"enter_your_email_": "dusan@thingsolver.com",
"enter_your_first_name": "Dusan"
}
}
You can see the similarity. It is important to put them in the fields block and add your client_name as a separate field. Now when you send the post request you will receive the response that data is collected successfully:
{
"FailedRecordCount": 0,
"Records": [
{
"SequenceNumber": "49643497478260951379093365276472448616841718436749901826",
"ShardId": "shardId-000000000000"
}
]
}
See the collected prospects
To see the collected prospects you can check the corresponding segment that has the same ID as your form_id by calling the endpoint
Method GET: https://dev.thingsolver.com/api/latest/segmentation-studio/segments/form-id-f0cd7b98123847b58f314401838f11f6
{
"segment_id": "form-id-9face8d6f9254401a5d689873988a406",
"segment_name": "My CS register Form",
"segment_type": "prospects",
"source": "forms",
"author": "Dusan Mijatovic",
"status": "created",
"is_dynamic": false,
"recommendations_export": {
"export_type": "recommender",
"recommendations_type": "best-sellers",
"number_of_recommendations": 10,
"filter_by": "default"
},
"filter_groups": [],
"column_names": [
"enter_your_email",
"enter_your_first_name",
"submit"
],
"is_ready": null,
"segment_size": 12,
"date_created": "2024-10-23T10:21:26",
"date_modified": "2024-10-23T12:37:31",
"last_used_datetime": "2024-10-23T12:22:55",
"last_used_action": "preview",
"last_used_in_studio": "segmentation"
}
As you can see our segment count is now 1 which is the number of records that we have sent in this example, if you send more records the value will increase every few minutes. To see exact customers in your segment you can call the next endpoint.
Method GET: https://dev.thingsolver.com/api/latest/segmentation-studio/segments/form-id-9face8d6f9254401a5d689873988a406/customers
And response will return a preview of customers in your list:
{
"offset": 0,
"limit": 10,
"count": 1,
"customers": [
{
"client_name": "dev",
"form_id": "form-id-9face8d6f9254401a5d689873988a406",
"enter_your_email": "dusan@thingsolver.com",
"enter_your_first_name": "Dusan"
}
]
}
If you want to receive data in the file format of CSV or Excel you can call the last endpoint
Method: GET https://dev.thingsolver.com/api/latest/customer-studio/segments/form-id-9face8d6f9254401a5d689873988a406/export
And in just several seconds you will receive an email with the download link. By opening the file we will see that there is the same record that we have entered via our integration.