서명이 필요한 대부분의 제품은 서명을 받기 위해 사용자를 다른 곳으로 보냅니다. 이메일이 도착하고, 링크를 열면 여러분의 제품과 전혀 닮지 않은 페이지가 나타나고, 사용자는 거기서 서명한 뒤 알아서 돌아오며, 여러분의 시스템은 누군가 확인해 봐야 비로소 무언가 일어났음을 알게 됩니다. 동작은 하지만, 모든 흐름이 끊기는 지점이 바로 여기입니다. 오늘부터 이것이 유일한 선택지가 아니게 됩니다. GingerDocs API와 임베드 SDK가 정식 출시되었으며, 문서는 app.gingerdocs.com/docs에, 두 SDK 패키지는 npm에 올라와 있습니다.

이 글은 이것으로 무엇을 만들 수 있는지를, 실제로 만들게 될 순서대로 짧게 정리한 것입니다.

세 단계: 발급, 마운트, 이벤트 처리

모델은 의도적으로 작게 설계했습니다. 서버가 당사 API에 임베드 세션을 요청합니다. 하나의 문서와 한 명의 서명자, 또는 여러분의 사용자 한 명과 워크스페이스에 묶인, 짧게 유효한 URL입니다. 페이지가 그 URL을 SDK에 넘기면, SDK는 당사 오리진에서 서명 화면을 프레임으로 띄우고 양쪽에서 오리진과 세션 id를 고정합니다. 그다음 여러분의 코드는 타입이 지정된 이벤트를 수신해 처리합니다.

시크릿 키는 브라우저에 절대 도달하지 않습니다. 이것은 여러분이 지켜야 할 지침이 아니라, 설계상 그럴 필요가 없는 것입니다. 페이지가 보는 것은 세션 URL뿐이고, 이 URL은 스스로 만료되며 서버에서 언제든 취소할 수 있기 때문입니다.

  • 서버에서 시크릿 키로 세션을 발급합니다. 문서와, 프레임을 띄울 페이지의 오리진을 지정하는 POST 한 번이면 됩니다.
  • SDK로 프레임을 마운트합니다. 페이지에서는 네 줄, React에서는 컴포넌트 하나입니다.
  • 이벤트를 처리합니다. ready, viewed, signed, completed, declined, 그리고 워크스페이스 세션의 문서 이벤트입니다. 프레임 밖에서 완료되는 모든 일에 대해서는 웹훅 엔드포인트나 이벤트 API가 신뢰할 수 있는 출처입니다.

코드

서버에서는 호출 한 번으로 세션을 만듭니다. 응답에는 페이지에 쓸 URL과, SDK가 그 세션의 메시지만 받아들이도록 함께 넘겨줄 id가 담겨 있습니다.

backend.jsJavaScript
const res = await fetch('https://api.gingerdocs.com/api/v1/embed_sessions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GINGERDOCS_SECRET_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    kind: 'signing',
    document_id: documentId,
    host_origin: 'https://app.example.com',
  }),
})
const { id, url } = await res.json()

페이지에서는 SDK가 아무 엘리먼트에나 프레임을 마운트하고 이벤트를 전달합니다. 세션이 만료되면 새 세션을 발급해 프레임을 그 자리에서 다시 불러오면 되므로, 서명자는 진행하던 위치를 잃지 않습니다.

frontend.jsJavaScript
import { mount } from '@gingerdocs/embed'

const embed = mount('#signing', { url, sessionId: id })

embed.on('ready', () => hideLoader())
embed.on('completed', () => showConfirmation())
embed.on('session_expired', async () => {
  const fresh = await refetchSession()
  embed.reload(fresh.url, { sessionId: fresh.id })
})

React를 사용한다면 모든 이벤트를 핸들러 하나로 받는 컴포넌트 하나이며, 인라인으로 넘겨도 안전합니다. React는 선택 사항입니다. 코어 패키지는 프레임워크에 의존하지 않으므로, 위의 네 줄은 Vue, Angular, Svelte 또는 순수 HTML 페이지에서도 그대로 동작합니다.

Signing.jsxJSX
import { GingerDocsEmbed } from '@gingerdocs/react'

<GingerDocsEmbed
  url={session.url}
  sessionId={session.id}
  onEvent={event => event.type === 'completed' && showConfirmation()}
/>

테스트 환경에서 무료로 만들기

개발자 모드와 테스트 키는 무료 요금제를 포함한 모든 요금제에서 쓸 수 있습니다. 이 글의 모든 내용은 테스트 환경에서 동작합니다. 어떤 종류의 이메일도 당사 서버 밖으로 나가지 않고, 출력 PDF에는 법적 효력이 없다는 워터마크가 찍히며, 테스트 문서는 90일 뒤 삭제됩니다. 테스트 엔드포인트로 서명을 시뮬레이션할 수도 있어, 사람이 아무것도 클릭하지 않아도 문서가 COMPLETED에 도달하는지를 CI에서 검증할 수 있습니다.

준비가 되면 라이브 키로 전환하세요. 호출은 완전히 동일합니다.

증명서에 적히는 여러분의 이름

완료된 모든 문서는 완료 증명서로 끝납니다. 참조번호, 검증 코드, 그리고 각 서명자의 타임라인과 IP 주소가 담깁니다. 서명 링크를 직접 전달했거나 임베드 세션을 통해 서명자의 신원을 보증한 경우, 증명서는 검증 당사자로 여러분의 법인명을 명시합니다. 이것이 개발자 모드를 켤 때 통합 파트너 약관에서 받아들이는 내용이며, 기록의 정직한 형태이기도 합니다. 누가 서명자를 보증했는지를 말해 주기 때문입니다.

PDF를 가진 사람은 누구나 계정 없이 검증 페이지에서 당사 기록과 대조해 확인할 수 있습니다.

웹훅, 그리고 90일 이벤트 로그

모든 상태 변화는 이벤트를 발생시킵니다. 웹훅 엔드포인트를 등록하면 각 이벤트가 서명된 POST로 도착하며, 재시도와 함께 설정 → 개발자에서 읽을 수 있는 전송 로그가 따릅니다. 엔드포인트가 한 시간 동안 다운되어 하나를 놓치더라도 그 이벤트는 여전히 남아 있습니다. 모든 이벤트는 API를 통해 90일 동안 읽을 수 있습니다.

프레임은 그 안에서 일어나는 일을 알려 주고, 웹훅은 어디에서 일어나든 알려 줍니다. 후자 위에 시스템을 세우고, 전자는 화면 앞에 있는 사람을 위해 쓰세요.

오픈소스, 패키지 두 개

SDK는 한 번에 다 읽을 수 있을 만큼 작으며, 그것이 핵심입니다. @gingerdocs/embed는 프레임워크에 의존하지 않고, gzip 기준 1.5 KB 미만이며, 의존성이 없습니다. @gingerdocs/react는 이를 컴포넌트 하나로 감쌉니다. 둘 다 MIT 라이선스이며 GitHub의 gingerdocs/embed-sdk와 gingerdocs/embed-react-sdk에 공개되어 있고, 이슈 트래커도 열려 있습니다.

읽을 수 있는 SDK가 있기에, 위의 보안 주장은 믿고 받아들이는 것이 아니라 직접 확인할 수 있는 것이 됩니다.

가격, 그리고 시작할 곳

테스트 키로는 무료로 만드세요. 라이브는 개발자 요금제로 갑니다. 연 $100에 프로의 모든 기능과 동일한 월 1,000건 문서 업로드, 그리고 라이브 API 키가 포함됩니다. 자세한 내용은 요금 페이지에 있습니다.

퀵스타트로 시작하세요. 새 계정에서 서명된 문서까지 네 번의 호출로, 터미널에서, 약 10분이면 됩니다. 개발자 페이지에 개요가 있고, 모든 필드가 필요할 때는 API 레퍼런스가 있습니다.