Kanorio

비즈니스 시스템

폼

Kanorio 폼을 자체 프론트엔드에 추가하세요. 봇 보호, 파일 업로드, 동의 확인, 연락처 수집 기능을 자동으로 처리합니다.

관리 화면의 마케팅 › 온라인 폼에서 폼을 만들고 프론트엔드에 표시합니다. Kanorio는 봇과 스팸을 확인하고, 제출 내용을 저장하며, 연락처를 생성하거나 업데이트하고, 확인 이메일과 팀 이메일을 발송하며, customers.form.submitted 웹훅을 실행합니다.

시작하기 전에 관리 화면에서 폼 ID를 복사하세요. 브라우저가 자체 도메인에서 API를 호출하는 경우, 사이트 설정 › 개발자의 허용된 오리진에 해당 도메인을 추가하세요. localhost는 항상 허용됩니다.

옵션 1: 폼 요소 사용

<KanorioForm>은 모든 질문 유형, 파일 업로드, 동의 체크박스를 렌더링하고 봇 보호 기능을 실행합니다. 가장 빠른 방법이며 업그레이드 없이도 새로운 보호 규칙이 적용됩니다.

import { KanorioProvider, KanorioForm } from "@kanorio/elements";
import "@kanorio/elements/elements.css";

export function ContactSection() {
  return (
    <KanorioProvider siteUrl="https://s-xxxxxxxxxxxx.kanorio.com">
      <KanorioForm formId="cform12345678901234567890" siteName="Sourdough Studio" />
    </KanorioProvider>
  );
}

React를 사용하지 않는 경우 <kanorio-form site-url="…" form-id="…">를 사용하세요. Elements를 참조하세요.

옵션 2: 자체 마크업 사용

HTML을 완전히 제어하고 싶다면 Content Delivery API를 직접 사용하세요.

1. 폼 불러오기

GET /api/v1/forms/{id}는 질문, 동의 설정, 폼의 응답 수락 여부를 반환합니다. availability.accepting이 false인 경우 입력란 대신 종료 메시지를 표시하세요.

2. 폼 표시 시 봇 체크 가져오기

GET /api/v1/forms/{id}/challenge는 해당 제출에 대한 봇 체크를 반환합니다. provider는 사이트 소유자가 사이트 설정 › 봇 보호에서 설정합니다.

  • kanorio (기본값): altcha에 내장된 작업 증명(proof-of-work) 챌린지입니다. SDK가 자동으로 해결하며(중급 사양 휴대폰에서 약 0.5초 소요), 결과를 _tk로 전송합니다.
  • turnstile, recaptcha, hcaptcha: 소유자의 자체 키입니다. 해당 제공업체의 위젯을 siteKey 및 action(Turnstile의 경우 cData 포함)으로 렌더링하고, 토큰을 captchaToken으로 전달하세요. 서버는 사이트 설정에서 검증할 제공업체를 결정하므로 다른 제공업체의 토큰은 거부됩니다.

제출할 때마다 새로운 챌린지를 가져오세요. 챌린지와 위젯 토큰은 1회용입니다.

3. 제출

질문 ID를 키로 하는 답변을 보호 필드와 함께 전송하세요. 허니팟(honeypot) 필드는 비어 있어야 합니다.

import { forms } from "@kanorio/sdk/forms";

const SITE_URL = "https://s-xxxxxxxxxxxx.kanorio.com";
const FORM_ID = "cform12345678901234567890";
const client = forms.client({ siteUrl: SITE_URL });

// when the form is shown
const renderedAt = Date.now();
const challenge = await client.challenge(FORM_ID);

// when the visitor submits
// built-in: the SDK solves the challenge; third-party: pass the widget token
const protection = await forms.protectionFromChallenge(FORM_ID, challenge, renderedAt, {
  captchaToken: challenge.provider === "kanorio" ? undefined : widgetToken,
});

const result = await client.submit(FORM_ID, {
  answers: { name: "Ada", email: "ada@example.com", message: "Do you ship?" },
  consent: "checked",
  pagePath: window.location.pathname,
  protection,
});

if (!result.ok) {
  // result.error.code, and result.error.issues for INVALID_ANSWERS
}

SDK를 사용하지 않는 경우, 다음 본문으로 POST /api/v1/forms/{id}/submit을 호출하세요(내장 체크 기준; 타사 제공업체 사용 시 _tk 대신 captchaToken 전송):

{
  "answers": { "name": "Ada", "email": "ada@example.com" },
  "consent": "checked",
  "pagePath": "/contact",
  "_hp": "",
  "_ts": 1793520000000,
  "_tk": "<solved ALTCHA payload>",
  "_ctx": "cform12345678901234567890"
}

제출에 성공하면 200 상태 코드와 {}를 반환합니다. 그 사이에 폼이 닫혔다면 본문은 { "state": "closed" }, "not_open", 또는 "full"이 됩니다.

오류 코드조치 방법
INVALID_ANSWERSdetails.issues에 포함된 메시지를 질문 ID별로 표시합니다
VERIFICATION_EXPIRED새로운 챌린지를 가져와(위젯 초기화) 다시 제출합니다
DUPLICATE_SUBMISSION양식이 이미 제출되었음을 방문자에게 알립니다
RATE_LIMITEDRetry-After 시간까지 대기한 후 다시 시도합니다

파일 업로드

파일 질문의 경우, 먼저 POST /api/v1/forms/{id}/upload-request로 업로드 티켓을 요청하세요. 이때 질문 ID, 파일 이름, 유형, 크기를 forms.uploadProtectionFromChallenge(FORM_ID, challenge, renderedAt, solved)에서 얻은 보호 필드와 함께 전송합니다. 내장 체크를 사용하는 경우 이는 제출 시 사용하는 해결된 챌린지와 동일하며, 타사 제공업체를 사용하는 경우 챌린지의 uploadToken을 사용합니다(위젯 토큰은 1회용이며 제출 시 확인되기 때문). 반환된 headers를 사용하여 uploadUrl에 PUT으로 파일을 업로드한 다음, uploadId를 해당 질문의 답변으로 전송하세요. 질문의 제한 용량을 초과하는 파일은 413 FILE_TOO_LARGE 오류가 발생합니다.

제출 후

  • 제출 내용은 관리 화면과 Management API의 submissions에서 확인할 수 있습니다.
  • 이메일 또는 전화번호 답변을 바탕으로 연락처가 생성되거나 업데이트됩니다.
  • 폼 설정에 따라 확인 이메일과 팀 이메일이 발송됩니다.
  • 웹훅 구독자에게 customers.form.submitted가 전달됩니다.

서버에서 전달하기

Next.js 서버 액션과 같이 자체 서버에서 제출할 수 있습니다. 속도 제한은 방문자별로 적용되므로 브라우저에서 직접 제출하는 것이 할당량을 보호하는 데 가장 좋습니다. 서버에서 전달하는 경우 브라우저의 보호 필드를 변경하지 마세요.