1.1.1 Add the following snippet at the position where the widget should be displayed on your page:
<div id="heyscore-widget"></div>
1.1.2 Apply the minimal configuration on each page where you want the widget to appear.
Note: Replace <<TOUCHPOINT_TOKEN>> with your real touchpoint token. You will find the token for each touchpoint at the integration page of your account.
<script src="https://www.heyscore.net/widget.js"></script>
<script>
window.HeyScoreConfig = {
touchpoint: "<<TOUCHPOINT_TOKEN>>",
target: "#heyscore-widget",
lang: "de",
};
</script>
1.1.3 Load the script on each page.
<script src="https://www.heyscore.net/widget.js"></script>
1.1.4 Optional: Extend the configuration to include custom meta data that will be attached to the submitted feedback. You can define your own key:value pairs.
<script>
window.HeyScoreConfig = {
touchpoint: "<<TOUCHPOINT_TOKEN>>",
target: "#heyscore-widget",
lang: "de",
meta: {
orderId: "2025-000123",
customerId: "cust_789",
productId: "prod_123"
}
};
</script>
Alternatively, you can update or add meta data dynamically at any time using the widget API:
<script>
window.HeyScoreWidget?.updateMeta({
orderId: "2025-000123",
customerId: "cust_789",
productId: "prod_123"
});
</script>
1.1.1 A standard HeyScore link looks like this. It will direct users to a HeyScore feedback form.
Note: Replace <<TOUCHPOINT_TOKEN>> with your real touchpoint token. You will find the token for each touchpoint at the integration page of your account.
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>
1.1.2 If you prefer to show the score options at your application, you can attach the score values 0 to 10 to the link:
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/0
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/1
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/2
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/3
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/4
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/5
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/6
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/7
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/8
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/9
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/10
With this option, you are able to create your own UX, for example:
<div class="hsc_wrapper">
<div class="hsc_question">How likely is it that you would recommend us to a friend or colleague?</div>
<div class="hsc_row_1">
<a class="hsc_score hsc_score_0" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/0"><span>0</span></a>
<a class="hsc_score hsc_score_1" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/1"><span>1</span></a>
<a class="hsc_score hsc_score_2" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/2"><span>2</span></a>
<a class="hsc_score hsc_score_3" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/3"><span>3</span></a>
<a class="hsc_score hsc_score_4" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/4"><span>4</span></a>
<a class="hsc_score hsc_score_5" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/5"><span>5</span></a>
</div>
<div class="hsc_row_2">
<a class="hsc_score hsc_score_6" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/6"><span>6</span></a>
<a class="hsc_score hsc_score_7" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/7"><span>7</span></a>
<a class="hsc_score hsc_score_8" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/8"><span>8</span></a>
<a class="hsc_score hsc_score_9" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/9"><span>9</span></a>
<a class="hsc_score hsc_score_10" href="https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>/10"><span>10</span></a>
</div>
<div class="hsc_legend">
<div class="hsc_legend_left">0 - Not at all likely</div>
<div class="hsc_legend_right">10 - Extremely likely</div>
</div>
</div>
<style>
.hsc_wrapper {
text-align:center;
margin: 1em auto;
max-width: 600px;
width: 100%;
font: 18px/1.5 sans-serif;
}
.hsc_wrapper .hsc_score {
display: inline-block;
position: relative;
width: 44px;
height: 44px;
line-height: 44px;
border-radius: 100%;
border: 2px solid;
padding:0;
margin-right: 0px;
background-color: black;
color:white;
font: 18px/1.5 sans-serif;
cursor: pointer;
text-decoration: none;
}
.hsc_wrapper .hsc_score span {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.hsc_wrapper .hsc_row_1, .hsc_wrapper .hsc_row_2 {
display: inline-block;
text-align:center;
width: 100%;
}
.hsc_wrapper .hsc_legend {
overflow: auto;
font-size: 85%;
}
.hsc_wrapper .hsc_legend_left, .hsc_wrapper .hsc_legend_right {
float:left;
width:50%;
}
.hsc_wrapper .hsc_legend_left {
text-align:left;
}
.hsc_wrapper .hsc_legend_right {
text-align:right;
}
.hsc_wrapper .hsc_text {
width:100%;
height: 100px;
font: 18px/1.5 sans-serif;
}
.hsc_submit {
width:100%;
height: 48px;
color: white;
background-color: black;
border: 0px solid;
font: 18px/1.5 sans-serif;
cursor: pointer;
}
@media(min-width:630px) {
.hsc_wrapper .hsc_row_1, .hsc_wrapper .hsc_row_2 {
width: auto;
}
}
@media(min-width:630px) {
.hsc_wrapper .hsc_legend {
max-width: none;
}
}
</style>
1.2.3 Optional: To add meta data, attach query parameters:
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>?key=value
You can add multiple fields by separating them with & (encoded as &). Example:
https://www.heyscore.net/fb/cl/<<TOUCHPOINT_TOKEN>>?customerId=12345&orderId=98765
Use the External API to send feedback from your own systems (CRM, backend, custom frontend, mobile app) directly to HeyScore when embedding the widget or link is not an option. It keeps dashboards in sync by routing every payload through the same campaign validation as native submissions.
2.1.1 Send POST requests to https://www.heyscore.net/api/v1/touchpoints/<<TOUCHPOINT_TOKEN>>/feedback. The token is identical to the one shown on the integration page.
2.1.2 Quick example request (including headers and payload):
curl -X POST https://www.heyscore.net/api/v1/touchpoints/<<TOUCHPOINT_TOKEN>>/feedback
-H "Content-Type: application/json"
-H "Api-Key: <<PUBLIC_KEY>>"
-H "Api-Secret: <<PLAIN_SECRET>>"
-d '{"score":9,"comment":"Great service","externalId":"crm-123","meta":{"orderId":"2026-00045"}}'
2.1.3 Required headers:
Content-Type: application/json – indicates that the body is JSON.Api-Key – public key of your API credential.Api-Secret – matching plain secret; only valid secrets pass authentication.2.1.4 Manage credentials under Config → API Credentials. Only team owners can create or revoke them, your subscription must include the API feature.
2.1.5 Keep the secret confidential. It is displayed exactly once right after creation, hashed immediately afterwards, and cannot be recovered—revoke the credential and generate a new one if you ever need to rotate it.
2.2.1 The payload must be valid JSON. Example:
{
"score": 9,
"comment": "Great service",
"externalId": "crm-123",
"submittedAt": "2026-03-13T10:15:00Z",
"meta": {
"customerId": "C-42",
"orderId": "2026-00045"
}
}
Field reference:
score (required integer): must stay within the campaign’s score scale (default 0–10). Missing, non-numeric, or out-of-range values return 400 invalid_score.comment (optional string): trimmed text stored when the campaign has a text question. Prefer comment for new integrations; the legacy alias text remains accepted but should only be used for backward compatibility. Empty strings are ignored.externalId (optional string): deduplication key per touchpoint + API source. Reusing it updates the same feedback, keeps the feedbackToken, overwrites score/comment/meta/date, and sets deduplicated to true.submittedAt (optional ISO 8601 datetime): overrides the feedback timestamp. If omitted, the server time is used; invalid values return 400 invalid_payload. Updating without this field refreshes the timestamp to the current server time.meta (optional object): arbitrary key/value pairs merged into the feedback metadata. Keys you send overwrite previous values, omitted keys remain untouched. Non-object values return 400 invalid_meta.Deduplication via externalId: sending the same identifier (e.g. crm-123) again does not create a new record—it updates the existing entry for that touchpoint, which is useful for retries or syncing edits from your system.
If the campaign/touchpoint has the Smart Follow-Ups feature enabled, the API may reply with a follow-up question that you can present in your channel (web, mobile, chatbot, etc.).
The initial response contains a state and optionally a followUp block:
{
"status": "accepted",
"feedbackToken": "fbk_123",
"state": "follow_up_required",
"followUp": {
"id": "sf_9v7m3k",
"question": "Could you describe what went wrong with the delivery?"
}
}
Interpretation:
state = completed: no follow-up question → stop after the initial submission.state = follow_up_required: show the provided followUp.question to the customer and submit their answer via a second call (see below).state = follow_up_answered: the deduplication logic found an existing answer, so you do not need to ask again.2.3.1 Follow-up submissions require feedbackToken + followUp only:
{
"feedbackToken": "fbk_123",
"followUp": {
"id": "sf_9v7m3k",
"answer": "We had to wait another week before someone replied."
}
}
Do not resend the original score/comment fields in the follow-up request; they would be ignored or rejected. If Smart Follow-Ups are disabled, you can skip this step entirely.
2.4.1 Successful initial requests return 201 Created:
{
"status": "accepted",
"deduplicated": false,
"feedbackToken": "6b1fd2...",
"state": "completed"
}
deduplicated becomes true when an existing entry (same touchpoint + externalId) was updated. feedbackToken is included once a token exists so you can continue other HeyScore flows that expect it. The state indicates whether a follow-up is required.
2.4.2 Follow-up submissions respond with 200 OK:
{
"status": "follow_up_recorded",
"state": "follow_up_answered"
}
Error responses share this format:
{
"error": "invalid_score",
"message": "Score must be between 0 and 10"
}
Typical error codes:
unauthorized (401) – missing headers, invalid key/secret pair, or revoked credential.feature_disabled (403) – the team’s subscription does not include the api_ingest feature.unknown_touchpoint (404) – token not found, inactive, or not linked to the authenticated team/campaign.invalid_payload (400) – malformed JSON or unsupported field value (e.g. invalid submittedAt).invalid_score (400) – score missing, non-numeric, or outside the campaign scale.invalid_meta (400) – meta is not a JSON object.unsupported_survey_type (400) – campaign currently uses a survey type other than NPS.invalid_follow_up (400) – second submission contained an empty answer or the wrong followUp.id.unknown_feedback (404) – feedbackToken does not belong to the authenticated touchpoint.