Skip to content

Form Studio

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

response
{
  "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",
      "audience_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

Auth Request
{
"username": "<enter-your-account-email>",
"password": "<enter-your-account-password>"
}

Response

Auth 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:

Auth Request
{"Authorization": "Bearer <access-token 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.

Response
{
    "offset": 0,
    "limit": 1,
    "templates": [
        {
            "form_template_name": "Register Form",
            "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

Request
{
    "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:

Response
{
    "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": "2023-08-17T14:56:49",
    "date_modified": "2023-08-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", "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" }

Response
{
    "form_name": "My CS register form",
    "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:

Response
{
    "form_name": "My CS register form",
    "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",
    "audience_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 audience. 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

Request
{
    "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.

Request
{
            "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": []
        }
Request
{
    "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:

Response
{
    "FailedRecordCount": 0,
    "Records": [
        {
            "SequenceNumber": "49643497478260951379093365276472448616841718436749901826",
            "ShardId": "shardId-000000000000"
        }
    ]
}

See the collected prospects

To see the collected prospects you can check the corresponding audience that has the same ID as your form_id by calling the endpoint

Method GET: https://dev.thingsolver.com/api/latest/customer-studio/audiences/form-id-9face8d6f9254401a5d689873988a406

Response
{
    "audience_id": "form-id-9face8d6f9254401a5d689873988a406",
    "audience_name": "My CS register form Form",
    "audience_type": "leads",
    "author": "Dusan",
    "status": "created",
    "is_dynamic": false,
    "recommendations_export": {
        "export_type": "recommender",
        "recommendations_type": "default",
        "number_of_recommendations": 10
    },
    "filters": [],
    "is_uploaded": false,
    "is_ready": null,
    "audience_size": 1,
    "date_created": "2023-08-17T15:08:46",
    "date_modified": "2023-08-17T15:24:45"
}

As you can see our audience 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 audience you can call the next endpoint.

Method GET: https://dev.thingsolver.com/api/latest/customer-studio/audiences/form-id-9face8d6f9254401a5d689873988a406/customers

And response will return a preview of customers in your list:

Response
{
    "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/audiences/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.

Back to top