---
title: "Calendly 커넥터"
description: "Tajo를 통해 Calendly의 스케줄링 이벤트, 초대자 데이터, 미팅 워크플로우를 Brevo와 동기화하는 완벽 가이드입니다."
url: https://tajo.io/kr/docs/connectors/custom/calendly/
markdown: https://tajo.io/kr/docs/connectors/custom/calendly.md
lang: ko-KR
robots: noindex
---

Tajo 사전 이용 신청

이름과 회사 이메일 주소를 입력하세요. Tajo 이용 신청을 확인할 수 있는 링크를 이메일로 보내드립니다.

# Calendly 커넥터

커넥터 상태: 예정 아직 구축되지 않았습니다. Tajo는 현재 이 커넥터를 실행하지 않습니다.

| 원본 필드 | 대상 필드 | 예시 값 |
| --- | --- | --- |
| `record.id` | `source_id` | `record_1042` |
| `record.updated_at` | `updated_at` | `2026-10-18T08:00:00Z` |
| `record.value` | `value` | `sample_value` |

Tajo를 통해 Calendly를 Brevo에 연결하여 미팅 초대자를 자동으로 연락처로 동기화하고, 예약 이벤트 기반의 이메일 시퀀스를 트리거하며, 영업 및 온보딩 워크플로우를 효율화하세요.

## 개요

| 속성 | 값 |
| --- | --- |
| **플랫폼** | Calendly |
| **카테고리** | Scheduling (Custom) |
| **설정 난이도** | 쉬움 |
| **공식 통합** | 아니오 |
| **동기화되는 데이터** | 이벤트, 연락처, 예약, 취소 |
| **인증 방식** | OAuth 2.0 / Personal Access Token |

## 주요 기능

- **초대자 동기화** - 미팅 초대자로부터 Brevo 연락처를 자동으로 생성합니다
- **예약 트리거** - 미팅이 예약되면 Brevo 자동화를 실행합니다
- **취소 처리** - 취소 시 재참여 플로우를 트리거합니다
- **노쇼 감지** - 초대자가 미팅을 놓쳤을 때 연락처 상태를 업데이트합니다
- **이벤트 타입 매핑** - 다양한 Calendly 이벤트 타입을 Brevo 리스트에 매핑합니다
- **Scheduling API** - 리디렉션 없이 앱에 스케줄링을 직접 구축합니다

## 사전 준비 사항

시작하기 전에 다음 사항이 준비되어 있어야 합니다.

1. Calendly 계정 (API 액세스를 위한 Professional 플랜 이상)
2. [Calendly Integrations](https://calendly.com/integrations)에서 발급한 Personal Access Token
3. API 액세스가 활성화된 Brevo 계정
4. 커넥터 권한이 있는 Tajo 계정

## 인증

### Personal Access Token

```bash
# Generate at https://calendly.com/integrations/api_webhooks
export CALENDLY_ACCESS_TOKEN=your_personal_access_token
export TAJO_API_KEY=your_tajo_api_key
export BREVO_API_KEY=your_brevo_api_key
```

### OAuth 2.0

```javascript
// OAuth 2.0 Authorization Code Flow
const authUrl = 'https://auth.calendly.com/oauth/authorize?' +
  new URLSearchParams({
    client_id: process.env.CALENDLY_CLIENT_ID,
    redirect_uri: 'https://your-app.com/callback',
    response_type: 'code'
  });

// Exchange code for token
const tokenResponse = await fetch('https://auth.calendly.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authorizationCode,
    client_id: process.env.CALENDLY_CLIENT_ID,
    client_secret: process.env.CALENDLY_CLIENT_SECRET,
    redirect_uri: 'https://your-app.com/callback'
  })
});
```

## 설정

### 기본 설정

```yaml
connectors:
  calendly:
    enabled: true
    access_token: "${CALENDLY_ACCESS_TOKEN}"

    sync:
      contacts: true
      events: true
      cancellations: true

    event_mapping:
      discovery_call:
        list_id: 10
        event_type_uri: "https://api.calendly.com/event_types/abc123"
      demo:
        list_id: 11
        event_type_uri: "https://api.calendly.com/event_types/xyz789"

    webhook:
      signing_key: "${CALENDLY_WEBHOOK_SIGNING_KEY}"
```

### 필드 매핑

```yaml
field_mapping:
  email: email
  name: FIRSTNAME
  questions_and_answers:
    company: COMPANY
    role: JOB_TITLE
    phone: SMS
  event_type_name: CALENDLY_EVENT_TYPE
  scheduled_at: MEETING_DATE
  status: BOOKING_STATUS
```

## API 엔드포인트

| 엔드포인트 | Method | 설명 |
| --- | --- | --- |
| `https://api.calendly.com/users/me` | GET | 현재 사용자 조회 |
| `https://api.calendly.com/event_types` | GET | 이벤트 타입 목록 |
| `https://api.calendly.com/scheduled_events` | GET | 예약된 이벤트 목록 |
| `https://api.calendly.com/scheduled_events/{uuid}` | GET | 예약된 이벤트 조회 |
| `https://api.calendly.com/scheduled_events/{uuid}/invitees` | GET | 초대자 목록 |
| `https://api.calendly.com/scheduling_links` | POST | 스케줄링 링크 생성 |
| `https://api.calendly.com/webhook_subscriptions` | POST | 웹훅 생성 |
| `https://api.calendly.com/webhook_subscriptions` | GET | 웹훅 목록 |
| `https://api.calendly.com/invitee_no_shows/{uuid}` | GET | 노쇼 상태 조회 |

## 코드 예제

### 커넥터 초기화

```javascript
import { TajoClient } from '@tajo/sdk';

const tajo = new TajoClient({
  apiKey: process.env.TAJO_API_KEY,
  brevoApiKey: process.env.BREVO_API_KEY
});

await tajo.connectors.connect('calendly', {
  accessToken: process.env.CALENDLY_ACCESS_TOKEN
});
```

### 예약된 이벤트 목록 조회

```javascript
// Retrieve scheduled events
const response = await fetch(
  'https://api.calendly.com/scheduled_events?' +
    new URLSearchParams({
      user: 'https://api.calendly.com/users/YOUR_USER_ID',
      min_start_time: '2024-01-01T00:00:00Z',
      max_start_time: '2024-12-31T23:59:59Z',
      status: 'active',
      count: 100
    }),
  {
    headers: {
      'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`,
      'Content-Type': 'application/json'
    }
  }
);

const events = await response.json();
```

### 초대자를 Brevo로 동기화

```javascript
// Get invitees for a scheduled event and sync to Brevo
const inviteesResponse = await fetch(
  `https://api.calendly.com/scheduled_events/${eventUuid}/invitees`,
  {
    headers: {
      'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`
    }
  }
);

const { collection } = await inviteesResponse.json();

for (const invitee of collection) {
  await tajo.contacts.sync({
    email: invitee.email,
    attributes: {
      FIRSTNAME: invitee.name,
      CALENDLY_EVENT_TYPE: invitee.event,
      MEETING_DATE: invitee.created_at,
      BOOKING_STATUS: invitee.status
    },
    listIds: [10]
  });
}
```

### 웹훅 구독 설정

```javascript
// Subscribe to Calendly events
const webhook = await fetch(
  'https://api.calendly.com/webhook_subscriptions',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: 'https://api.example.com/webhooks/calendly',
      events: [
        'invitee.created',
        'invitee.canceled',
        'invitee_no_show.created'
      ],
      organization: 'https://api.calendly.com/organizations/YOUR_ORG_ID',
      scope: 'organization',
      signing_key: process.env.CALENDLY_WEBHOOK_SIGNING_KEY
    })
  }
);
```

Caution

위의 `example.com` 주소는 Tajo 엔드포인트가 제공될 때까지 사용하는 자리표시자입니다.

### 웹훅 이벤트 처리

```javascript
app.post('/webhooks/calendly', async (req, res) => {
  // Verify webhook signature
  const signature = req.headers['calendly-webhook-signature'];
  const isValid = verifyCalendlySignature(
    req.rawBody, signature, process.env.CALENDLY_WEBHOOK_SIGNING_KEY
  );

  if (!isValid) return res.status(401).send('Unauthorized');

  const { event, payload } = req.body;

  switch (event) {
    case 'invitee.created':
      await tajo.contacts.sync({
        email: payload.email,
        attributes: { BOOKING_STATUS: 'booked' },
        listIds: [10]
      });
      break;
    case 'invitee.canceled':
      await tajo.contacts.update(payload.email, {
        attributes: { BOOKING_STATUS: 'cancelled' }
      });
      break;
    case 'invitee_no_show.created':
      await tajo.contacts.update(payload.email, {
        attributes: { BOOKING_STATUS: 'no_show' }
      });
      break;
  }

  res.status(200).send('OK');
});
```

## 요청 제한

| 리소스 | 제한 | 비고 |
| --- | --- | --- |
| API 요청 | 분당 6,000회 | 조직 전체 제한 |
| 웹훅 구독 | 조직당 30개 | 모든 이벤트 타입 합산 |
| 스케줄링 링크 | 무제한 | 분당 제한 없음 |

페이지네이션

Calendly API 응답은 커서 기반 페이지네이션을 사용합니다. `pagination` 객체의 `next_page_token`을 사용해 추가 결과를 가져오세요. 기본 페이지 크기는 20개 항목이며, 최대 100개입니다.

## 문제 해결

| 문제 | 원인 | 해결 방법 |
| --- | --- | --- |
| 웹훅 수신 안 됨 | 잘못된 스코프 | 웹훅에 `organization` 스코프를 사용하세요 |
| 401 Unauthorized | 토큰 만료 | 새 토큰을 생성하거나 OAuth 토큰을 새로 고치세요 |
| 초대자 데이터 누락 | 질문이 구성되지 않음 | 이벤트 타입에 커스텀 질문을 추가하세요 |
| 중복 연락처 | 중복 제거 로직 없음 | upsert의 고유 식별자로 이메일을 사용하세요 |
| Rate limit 429 | 요청이 너무 많음 | 백오프와 요청 배치를 구현하세요 |

### 디버그 모드

```yaml
connectors:
  calendly:
    debug: true
    log_level: verbose
    log_webhooks: true
```

## 모범 사례

1. **웹훅 사용** - 실시간 동기화를 위해 `invitee.created`와 `invitee.canceled`를 구독하세요
2. **커스텀 질문 추가** - 더 풍부한 연락처 프로필을 위해 회사, 역할, 전화번호 데이터를 수집하세요
3. **이벤트 타입 매핑** - Calendly 이벤트 타입별로 다른 Brevo 리스트를 할당하세요
4. **노쇼 처리** - 리드 스코어링과 후속 시퀀스를 조정하기 위해 노쇼를 추적하세요
5. **스케줄링 링크 사용** - 맞춤형 예약 경험을 위해 고유 스케줄링 링크를 생성하세요
6. **조직 스코프 설정** - 모든 팀원의 이벤트를 캡처하려면 조직 수준 웹훅을 사용하세요

## 보안

- **OAuth 2.0** - 스코프 기반 토큰 인증
- **웹훅 서명** - 수신 웹훅에 대한 HMAC 서명 검증
- **HTTPS 전용** - 모든 API 엔드포인트는 TLS 암호화가 필요합니다
- **토큰 만료** - OAuth 토큰은 만료되며 새로 고침 플로우가 필요합니다
- **최소 스코프** - 필요한 OAuth 스코프만 요청하세요
- **안전한 저장** - 환경 변수 또는 시크릿 매니저에 토큰을 저장하세요

## 관련 리소스

- [Typeform 커넥터](https://tajo.io/kr/docs/connectors/custom/typeform)
- [Zoom 커넥터](https://tajo.io/kr/docs/connectors/custom/zoom)
- [Customer Sync Skill](https://tajo.io/kr/docs/skills/data-sync/customer-sync)
- [Calendly Developer API Documentation](https://developer.calendly.com/api-docs)
