웹훅
리스토베이 폼 제출 시, 다른 앱이나 URL로 정보를 보낼 수 있습니다.
작동 원리
응답자가 리스토베이 설문을 제출하면 응답 데이터가 포함된 알림이 POST 요청을 통해 JSON 형식으로 URL에 전송됩니다 .
연동 방법
1️⃣
결과/연동
메뉴 아래의외부 앱 연동
을 클릭해주세요.
2️⃣
- 웹훅
연결하기
클릭
- 설문 당 최대 3개 까지 등록 가능
3️⃣
✋ 설문별로 최대 3개 까지 등록할 수 있습니다
Endpoint URL
POST 메서드를 사용하여 웹훅 요청을 수락할 수 있는 HTTP 또는 HTTPS 엔드포인트를 설정합니다.
- JSON 페이로드로 POST 요청을 처리합니다.
- 3초 이내에 성공 상태 코드(2XX)를 반환합니다.
새 제출을 처리하고 응답하는 데 3초의 제한 시간이 있습니다.
처리 시간이 더 오래 걸리면 내부적으로 다른 서비스를 호출하는 것이 좋습니다.
Signing secret
Signing secret을 사용하여 해당 요청이 리스토베이 서버에서 온것인지 확인함으로써 웹훅을 보호합다.
- 이 옵션이 활성화되면 웹훅 요청에
Listovey-Signature
헤더가 포함됩니다.
- 이 헤더의 값은 웹훅 페이로드의 SHA256 암호화 해시입니다.
Node.js 예제
const crypto = require('crypto') app.use(express.json()); app.post('/webhook', (req, res) => { const payload = req.body; const listoveySignature = req.headers['listovey-signature']; // 'SIGNING_SECRET' 부분을 리스토베이에서 등록한 Signing secret 값으로 변경 const mySigningSecret = 'SIGNING_SECRET'; // signing secret과 payload를 사용하여 계산 const payloadSignature = crypto.createHmac('sha256', mySigningSecret) .update(JSON.stringify(payload)) .digest('base64'); // listoveySignature 와 payloadSignature 값을 비교 if (signature === payloadSignature) { // 유효한 서명 res.status(200).send('success.'); } else { // 유효하지 않은 서명 res.status(401).send('invalid signature.'); } });
Java 예제
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import static spark.Spark.*; public class Main { public static void main(String[] args) { post("/webhook", (req, res) -> { String payload = req.body(); String listoveySignature = req.headers("listovey-signature"); // 'SIGNING_SECRET' 부분을 리스토베이에서 등록한 Signing secret 값으로 변경 String mySigningSecret = "SIGNING_SECRET"; // signing secret과 payload를 사용하여 계산 String payloadSignature = calculateHmacSHA256(payload, mySigningSecret); // listoveySignature 와 payloadSignature 값을 비교 if (listoveySignature.equals(payloadSignature)) { // 유효한 서명 return "success."; } else { // 유효하지 않은 서명 return "invalid signature."; } }); } private static String calculateHmacSHA256(String data, String key) throws NoSuchAlgorithmException, InvalidKeyException { Mac sha256Hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA256"); sha256Hmac.init(secretKey); byte[] hmacData = sha256Hmac.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(hmacData); } }
Python 예제
import hashlib import hmac from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): payload = request.json listovey_signature = request.headers.get('listovey-signature') # 'SIGNING_SECRET' 부분을 리스토베이에서 등록한 Signing secret 값으로 변경 my_signing_secret = 'SIGNING_SECRET' # signing secret과 payload를 사용하여 계산 payload_signature = hmac.new(my_signing_secret.encode('utf-8'), msg=json.dumps(payload).encode('utf-8'), digestmod=hashlib.sha256).digest() payload_signature = payload_signature.hex() # listovey_signature 와 payload_signature 값을 비교 if listovey_signature == payload_signature: # 유효한 서명 return 'success.', 200 else: # 유효하지 않은 서명 return 'invalid signature.', 401 if __name__ == '__main__': app.run()
요청 실패 및 재시도
웹훅 엔드포인트가 3초 이내에 성공적인 상태 코드(2XX)를 반환하지 못하는 경우 재시도 메커니즘을 사용하여 제출 전달을 시도합니다. 재시도 순서는 다음과 같습니다.
웹훅 엔드포인트가 3초 이내에 성공적인 상태 코드(2XX)를 반환하지 못하는 경우 다음 규칙을 사용하여 엔드포인트에 대한 요청을 다시 시도합니다.
- HTTP 상태가
410 Gone
404 Not Found
로 수신되면 재시도가 수행되지 않고 웹후크가 즉시 비활성화되며 가입된 이메일 계정으로 안내 드립니다.
- 다른 HTTP 코드가 수신되면 5분, 30분, 1시간, 2시간, 6시간 후에 엔드포인트에 대한 요청을 5번 다시 시도합니다.
- HTTP 상태가
429 Too Many Requests
408 Timeout
503 Service Unavailable
423 Locked
으로 수신되면 재시도 시간에 1~3,000초 사이로 시간이 추가되어 다시 시도합니다.
자동 비활성화
하루 동안 100회 이상의 전달 시도로 100% 실패하는 경우 해당 웹훅을 중지하고 이메일 계정으로 안내해 드립니다.
웹훅 관리
웹훅 URL이 표시되고 토글을 클릭하면 웹훅 URL을 연결하고 일시중지할 수 있습니다.
이벤트 로그를 보려면 로그 버튼을 클릭합니다.
- 이 로그에는 웹훅 엔드포인트에 대한 최근 31일 동안의 요청을 확인 할 수 있습니다.
- 재발송 기능으로 실패한 이벤트에 대해 수동으로 다시 발송할 수 있습니다.
- 테스트 이벤트 발송으로 임의의 데이터를 받아 볼 수 있습니다. (플랜과 상관 없이 이용 가능)
웹훅을 수정 하시려면 [수정] 버튼을, 삭제 하시려면 [삭제] 버튼을 클릭 합니다.
웹훅 이벤트 예시
이 예제 이벤트에는 리스토베이가 지원하는 모든 유형의 필드가 포함되어 있습니다.
POST /[webhook_url] HTTP/1.1 "content-type": "application/json; charset=UTF-8" "user-agent": "Listovey webhook"
{ "eventId": "912ba841-32a8-4e64-b7f9-c92f480b0dfc", "eventType": "FORM_RESPONSE", "createdAt": "2024-03-05T03:26:37.430Z", "data": { "response": { "responseId": "R17E1Gc", "createdAt": "2024-03-05T03:26:37.402Z", "submittedAt": "2024-03-05T03:26:37.402Z" }, "form": { "formId": "S7877", "title": "전체문항", "fields": [ { "id": "Q114003", "no": 1, "title": "단일선택형", "type": "SINGLE-CHOICE", "choices": [ { "id": "_01163458", "text": "선택 1" }, { "id": "_01163459", "text": "선택 2" } ], "value": { "id": "_01163458", "commentValue": "TEST" } }, { "id": "Q114004", "no": 2, "title": "다중선택형", "type": "MULTI-CHOICE", "choices": [ { "id": "_0242743", "text": "선택 1" }, { "id": "_0242744", "text": "선택 2" } ], "value": [ { "id": "_0242743", "commentValue": "TEST" } ] }, { "id": "Q114005", "no": 3, "title": "드롭다운형", "type": "DROPDOWN", "choices": [ { "id": "_214436", "text": "옵션 1" }, { "id": "_214437", "text": "옵션 2" } ], "value": [ "_214436" ], "commentValue": "" }, { "id": "Q114006", "no": 4, "title": "단일선택형 매트릭스", "type": "SINGLE-MATRIX", "rows": [ { "id": "row_0318066", "text": "항목 1" }, { "id": "row_0318067", "text": "항목 2" } ], "columns": [ { "id": "col_0316013", "text": "선택 1" }, { "id": "col_0316014", "text": "선택 2" } ], "value": { "row_0318066": "col_0316013", "row_0318067": "col_0316013" }, "commentValue": "" }, { "id": "Q114007", "no": 5, "title": "다중선택형 매트릭스", "type": "MULTI-MATRIX", "rows": [ { "id": "row_044827", "text": "항목 1" }, { "id": "row_044828", "text": "항목 2" } ], "columns": [ { "id": "col_044000", "text": "선택 1" }, { "id": "col_044001", "text": "선택 2" } ], "value": { "row_044827": [ "col_044000" ], "row_044828": [ "col_044000" ] }, "commentValue": "TEST" }, { "id": "Q114008", "no": 6, "title": "이미지 단일선택형", "type": "SINGLE-IMAGE-CHOICE", "choices": [ { "id": "_1217029", "text": "선택 1" }, { "id": "_1217030", "text": "선택 2" } ], "value": { "id": "_1217029", "commentValue": "TEST" } }, { "id": "Q114009", "no": 7, "title": "이미지 다중선택형", "type": "MULTI-IMAGE-CHOICE", "choices": [ { "id": "_1311411", "text": "선택 1" }, { "id": "_1311412", "text": "선택 2" } ], "value": [ { "id": "_1311411", "commentValue": "" } ] }, { "id": "Q114010", "no": 8, "title": "가로형 평가척도", "type": "HORIZONTAL-SCALE", "choices": [ { "id": "_0558500", "no": 1 }, { "id": "_0558501", "no": 2 }, { "id": "_0558502", "no": 3 }, { "id": "_0558503", "no": 4 }, { "id": "_0558504", "no": 5 } ], "value": "_0558500", "commentValue": "" }, { "id": "Q114011", "no": 9, "title": "가로형 평가척도 그룹", "type": "HORIZONTAL-SCACLE-GROUP", "rows": [ { "id": "row_0610318", "text": "항목 1" }, { "id": "row_0610319", "text": "항목 2" } ], "columns": [ { "id": "col_0612615", "no": 1 }, { "id": "col_0612616", "no": 2 }, { "id": "col_0612617", "no": 3 }, { "id": "col_0612618", "no": 4 }, { "id": "col_0612619", "no": 5 } ], "value": { "row_0610318": "col_0612615", "row_0610319": "col_0612615" }, "commentValue": "" }, { "id": "Q114012", "no": 10, "title": "세로형 평가척도", "type": "VERTICAL-SCALE", "choices": [ { "id": "_0714754", "text": "선택 1", "no": 1 }, { "id": "_0714755", "text": "선택 2", "no": 2 }, { "id": "_0714756", "text": "선택 3", "no": 3 }, { "id": "_0714757", "text": "선택 4", "no": 4 }, { "id": "_0714758", "text": "선택 5", "no": 5 } ], "value": "_0714754", "commentValue": "" }, { "id": "Q114013", "no": 11, "title": "세로형 평가척도 그룹", "type": "VERTICAL-SCALE-GROUP", "rows": [ { "id": "row_081432", "text": "항목 1" }, { "id": "row_081433", "text": "항목 2" } ], "columns": [ { "id": "col_082006", "text": "선택 1", "no": 1 }, { "id": "col_082007", "text": "선택 2", "no": 2 }, { "id": "col_082008", "text": "선택 3", "no": 3 }, { "id": "col_082009", "text": "선택 4", "no": 4 }, { "id": "col_082010", "text": "선택 5", "no": 5 } ], "value": { "row_081432": "col_082006", "row_081433": "col_082006" }, "commentValue": "" }, { "id": "Q114014", "no": 12, "title": "추천형", "type": "RECOMMEND", "choices": [ { "id": "_146001", "text": "선택 1", "no": 1 }, { "id": "_146002", "text": "선택 2", "no": 2 }, { "id": "_146003", "text": "선택 3", "no": 3 }, { "id": "_146004", "text": "선택 4", "no": 4 }, { "id": "_146005", "text": "선택 5", "no": 5 } ], "value": "_146001", "commentValue": "" }, { "id": "Q114015", "no": 13, "title": "추천형 그룹", "type": "RECOMMEND-GROUP", "rows": [ { "id": "row_152142", "text": "항목 1" }, { "id": "row_152143", "text": "항목 2" } ], "columns": [ { "id": "col_153104", "text": "선택 1", "no": 1 }, { "id": "col_153105", "text": "선택 2", "no": 2 }, { "id": "col_153106", "text": "선택 3", "no": 3 }, { "id": "col_153107", "text": "선택 4", "no": 4 }, { "id": "col_153108", "text": "선택 5", "no": 5 } ], "value": { "row_152142": "col_153104", "row_152143": "col_153104" }, "commentValue": "" }, { "id": "Q114016", "no": 14, "title": "타입검사 입력형 - 텍스트", "type": "INPUT", "kind": "TEXT", "value": "TEST" }, { "id": "Q114048", "no": 15, "title": "타입검사 입력형 - 숫자", "type": "INPUT", "kind": "NUMBER", "value": "1" }, { "id": "Q114049", "no": 16, "title": "타입검사 입력형 - 이메일", "type": "INPUT", "kind": "EMAIL", "value": "test@listovey.com" }, { "id": "Q114050", "no": 17, "title": "타입검사 입력형 - 전화번호", "type": "INPUT", "kind": "PHONE", "value": "+82 0100000000" }, { "id": "Q114051", "no": 18, "title": "타입검사 입력형 - 날짜", "type": "INPUT", "kind": "DATE", "value": "2024-03-05" }, { "id": "Q114042", "no": 19, "title": "장문 서술형", "type": "TEXTAREA", "value": "TEST 1\nTEST 2\nEST 3" }, { "id": "Q114043", "no": 20, "title": "주소 입력형", "type": "ADDRESS", "value": { "zipcode": "01014", "address1": "서울 강북구 4.19로11길 6", "address2": "1130호" } }, { "id": "Q114044", "no": 21, "title": "D&D 순위형", "type": "RANKING-DRAG", "choices": [ { "id": "_113789", "text": "선택 1" }, { "id": "_113790", "text": "선택 2" }, { "id": "_113791", "text": "선택 3" } ], "value": [ "_113789", "_113790", "_113791" ], "commentValue": "" }, { "id": "Q114045", "no": 22, "title": "Click 순위형", "type": "RANKING-CLICK", "choices": [ { "id": "_177231", "text": "선택 1" }, { "id": "_177232", "text": "선택 2" }, { "id": "_177233", "text": "선택 3" } ], "value": [ { "id": "_177231", "commentValue": "" }, { "id": "_177232", "commentValue": "" } ] }, { "id": "Q114046", "no": 23, "title": "이미지 Click 순위형", "type": "RANKING-IMAGE-CLICK", "choices": [ { "id": "_181230", "text": "선택 1" }, { "id": "_181231", "text": "선택 2" }, { "id": "_181232", "text": "선택 3" } ], "value": [ { "id": "_181230", "commentValue": "" }, { "id": "_181231", "commentValue": "" } ] }, { "id": "Q114047", "no": 24, "title": "파일 업로드형", "type": "FILEUPLOAD", "value": { "filename": "best.png", "filetype": "image/png", "filesize": 46828, "src": "https://cdn.listovey.com/2205/4775/59855/5b358f18-2bfc-4925-9b06-a31aa64836fb2205477559855.png" }, "commentValue": "" }, { "type": "ENDING", "choices": [ { "id": "_E10142", "text": "완료글 1" }, { "id": "_E10143", "text": "완료글 2" } ], "value": "_E10142" }, { "type": "POINT", "value": 11 } ] } } }
Event information
ELEMENT | TYPE | DESCRIPTION |
eventId | string | 웹훅의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 36자로 고정됩니다. |
eventType | string | 테스트 이벤트 발송: TEST_RESPONSE
폼 제출: FORM_RESPONSE |
createdAt | string | 웹훅 이벤트 전송 시간입니다.
ISO 8601 형식의 UTC 시간을 사용합니다. |
object | response: 응답자의 정보
form: 폼 답변 정보 |
Response information
ELEMENT | TYPE | DESCRIPTION |
responseId | string | 응답자의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최소 7자, 최대 52자 입니다. |
createdAt | string | 응답자의 설문 최초 접속 시간입니다.
ISO 8601 형식의 UTC 시간을 사용합니다. |
submittedAt | string | 응답자의 설문 제출 시간입니다.
ISO 8601 형식의 UTC 시간을 사용합니다. |
Form information
ELEMENT | TYPE | DESCRIPTION |
formId | string | 설문의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최소 3자, 최대 52자 입니다. |
title | string | 설문의 제목입니다. |
array | 설문 내 문항의 내용을 배열 형식으로 저장됩니다. |
Fields information
ELEMENT | ㅤ | TYPE | DESCRIPTION |
id | ㅤ | string | 설문 문항의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최대 52자 입니다. |
no | ㅤ | number | 설문 문항의 번호입니다. |
title | ㅤ | string | 설문 문항의 내용입니다. |
choices | ㅤ | object[] | 문항-보기 선택으로 구성된 문항에서 사용 |
ㅤ | id | string | 보기의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최대 52자 입니다. |
ㅤ | text | string | 보기의 내용입니다. |
ㅤ | no | number | 척도형 같이 범위의 순서를 나타내는 값 |
rows | ㅤ | object[] | 문항-항목-보기 선택으로 구성된 문항에서 사용하는
항목 부분 |
ㅤ | id | string | 항목의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최대 52자 입니다. |
ㅤ | text | string | 항목의 내용입니다. |
columns | ㅤ | object[] | 문항-항목-보기 선택으로 구성된 문항에서 사용하는
보기 부분 |
ㅤ | id | string | 항목의 고유 ID 이며, 자동으로 할당됩니다.
텍스트 길이는 최대 52자 입니다. |
ㅤ | text | string | 보기의 내용입니다. |
ㅤ | no | number | 척도형 같이 범위의 순서를 나타내는 값 |
ㅤ | string,
string[],
object,
object[] | 문항 종류에 따라 value 형태가 다릅니다.
| |
commentValue | ㅤ | string | 문항에 대한 코멘트 |
kind | ㅤ | string | 타입검사 입력형 유형
”TEXT”: 텍스트 입력
”NUMBER”: 숫자 입력
”EMAIL”: 이메일 입력
”PHONE”: 전화번호 입력
”DATE”: 날짜 입력 |
Value information
단일 선택형, 이미지 단일 선택형 (단일 선택이면서 각 보기마다 코멘트 추가할 수 있는 문항)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object | ㅤ |
ㅤ | id | string | 선택된 보기의 고유 ID |
ㅤ | commentValue | string | 선택된 보기의 코멘트 내용 (추가 여부와 상관없이 나타남) |
다중 선택형, 이미지 다중 선택형 (다중 선택이면서 각 보기마다 코멘트 추가할 수 있는 문항)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object[] | ㅤ |
ㅤ | id | string | 선택된 보기의 고유 ID |
ㅤ | commentValue | string | 선택된 보기의 코멘트 내용 (추가 여부와 상관없이 나타남) |
드롭다운형 (단일 / 다중 형태를 선택할 수 있는 문항)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | string[] | 선택된 보기의 고유 ID |
단일선택형 매트릭스, 가로형/세로형 평가척도 그룹, 추천형 그룹 (항목마다 단일 선택인 문항)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object[] | “key”: 항목의 고유 ID
”value”: 선택된 보기의 고유 ID |
다중선택형 매트릭스
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object[] | “key”: 항목의 고유 ID
”value[]”: 선택된 보기의 고유 ID |
가로형/세로형 평가척도, 추천형 (단일 선택 형태)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | string | 선택된 보기의 고유 ID |
타입검사 입력형, 장문 서술형 (답변이 text 형태)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | string | 답변 내용 |
주소 입력형
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object | ㅤ |
ㅤ | zipcode | string | 우편번호 |
ㅤ | address1 | string | 기본 주소 |
ㅤ | address2 | string | 상세 주소 |
D&D 순위형
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | string[] | 선택한 보기의 고유 ID
첫 번째 배열부터 1순위 |
Click 순위형, 이미지 Click 순위형 (순위형이면서, 각 보기마다 코멘트를 추가할 수 있는 문항)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object[] | ㅤ |
ㅤ | id | string | 선택한 보기의 고유 ID
첫 번째 배열부터 1순위 |
ㅤ | commentValue | string | 선택된 보기의 코멘트 내용 (추가 여부와 상관없이 나타남) |
파일 업로드형
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | object | ㅤ |
ㅤ | filename | string | 파일명 |
ㅤ | filetype | string | 파일 타입 |
ㅤ | filesize | number | 파일 크기 (byte) |
ㅤ | src | string | 파일이 저장된 주소 |
완료글 (2개 이상일 경우 나타남)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | string | 제출 후 도착한 완료글의 고유 ID |
포인트 (퀴즈 방식 - 포인트 합산 방식 사용시 나타남)
ELEMENT | ㅤ | TYPE | DESCRIPTION |
{value} | ㅤ | number | 포인트 값 |
스탠다드 / 프리미엄 플랜에서 이용 가능합니다.
이용 가이드
리스토베이를 훨씬 더 알차게 이용하실 수 있는 방법 지금부터 알려 드릴게요!
설문 제작, 처음이신가요?
유용한 설문 옵션
설문의 고수가 되는 길, 어렵지 않아요!
멤버십 서비스로 업무 능률 🚀
결제
자주 묻는 질문과 답변 (FAQ)
리스토베이에 제안하기
주요 기능을 한번에 확인하세요!