calendlyr 0.10.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +38 -0
- data/README.md +188 -4
- data/calendlyr.gemspec +4 -1
- data/docs/resources/activity_log/list_activity_log_entries.md +2 -1
- data/docs/resources/availabilities/user_availability_schedule.md +3 -2
- data/docs/resources/availabilities/user_busy_time.md +3 -2
- data/docs/resources/event_types/available_time.md +25 -0
- data/docs/resources/event_types/event_type.md +3 -2
- data/docs/resources/event_types/membership.md +28 -0
- data/docs/resources/events/event.md +4 -3
- data/docs/resources/events/invitee.md +2 -1
- data/docs/resources/events/invitee_no_show.md +2 -1
- data/docs/resources/groups/group.md +2 -1
- data/docs/resources/organizations/membership.md +3 -2
- data/docs/resources/organizations/organization.md +13 -0
- data/docs/resources/outgoing_communications/outgoing_communication.md +28 -0
- data/docs/resources/routing_forms/routing_form.md +2 -1
- data/docs/resources/routing_forms/submission.md +2 -1
- data/docs/resources/scheduling_links/scheduling_link.md +26 -0
- data/docs/resources/share.md +2 -1
- data/docs/resources/webhooks/invitee_payload.md +10 -16
- data/docs/resources/webhooks/payload.md +32 -3
- data/docs/resources/webhooks/sample.md +23 -0
- data/docs/resources/webhooks/subscription.md +10 -6
- data/lib/calendlyr/client.rb +3 -2
- data/lib/calendlyr/collection.rb +25 -7
- data/lib/calendlyr/configuration.rb +24 -0
- data/lib/calendlyr/error.rb +52 -5
- data/lib/calendlyr/object.rb +10 -1
- data/lib/calendlyr/objects/event_types/available_time.rb +8 -0
- data/lib/calendlyr/objects/event_types/membership.rb +8 -0
- data/lib/calendlyr/objects/outgoing_communication.rb +6 -0
- data/lib/calendlyr/objects/scheduling_link.rb +6 -0
- data/lib/calendlyr/objects/webhooks/payload.rb +30 -0
- data/lib/calendlyr/resource.rb +55 -10
- data/lib/calendlyr/resources/availability.rb +14 -2
- data/lib/calendlyr/resources/event_types.rb +33 -2
- data/lib/calendlyr/resources/events.rb +15 -2
- data/lib/calendlyr/resources/groups.rb +14 -2
- data/lib/calendlyr/resources/locations.rb +6 -1
- data/lib/calendlyr/resources/organizations.rb +25 -3
- data/lib/calendlyr/resources/outgoing_communications.rb +16 -0
- data/lib/calendlyr/resources/routing_forms.rb +14 -2
- data/lib/calendlyr/resources/scheduling_links.rb +11 -0
- data/lib/calendlyr/resources/shares.rb +1 -0
- data/lib/calendlyr/resources/webhooks.rb +13 -1
- data/lib/calendlyr/version.rb +1 -1
- data/lib/calendlyr/webhook.rb +105 -0
- data/lib/calendlyr.rb +51 -0
- data/logos/calendlyr.png +0 -0
- data/logos/calendlyr_bg_white.png +0 -0
- data/test/calendlyr/client_test.rb +15 -0
- data/test/calendlyr/collection_test.rb +107 -3
- data/test/calendlyr/configuration_test.rb +157 -0
- data/test/calendlyr/object_test.rb +50 -0
- data/test/calendlyr/objects/webhooks/payload_test.rb +15 -0
- data/test/calendlyr/resource_test.rb +287 -1
- data/test/calendlyr/resources/availabilities/user_busy_times_test.rb +26 -0
- data/test/calendlyr/resources/availabilities/user_schedules_test.rb +25 -0
- data/test/calendlyr/resources/event_types_test.rb +84 -0
- data/test/calendlyr/resources/events_test.rb +68 -0
- data/test/calendlyr/resources/groups_test.rb +54 -0
- data/test/calendlyr/resources/locations_test.rb +12 -0
- data/test/calendlyr/resources/organizations_test.rb +96 -2
- data/test/calendlyr/resources/outgoing_communications_test.rb +42 -0
- data/test/calendlyr/resources/routing_forms_test.rb +57 -0
- data/test/calendlyr/resources/scheduling_links_test.rb +40 -0
- data/test/calendlyr/resources/shares_test.rb +15 -0
- data/test/calendlyr/resources/webhooks_test.rb +66 -0
- data/test/calendlyr/webhook_test.rb +292 -0
- data/test/fixtures/activity_log/list_page2.json +30 -0
- data/test/fixtures/event_invitees/list_page2.json +35 -0
- data/test/fixtures/event_type_available_times/list.json +10 -0
- data/test/fixtures/event_type_memberships/list.json +43 -0
- data/test/fixtures/event_type_memberships/list_page2.json +33 -0
- data/test/fixtures/event_types/list_page2.json +37 -0
- data/test/fixtures/events/list_page2.json +29 -0
- data/test/fixtures/group_relationships/list_page2.json +35 -0
- data/test/fixtures/groups/list_page2.json +16 -0
- data/test/fixtures/locations/list_page2.json +16 -0
- data/test/fixtures/organizations/list_invitations_page2.json +18 -0
- data/test/fixtures/organizations/list_memberships_page2.json +26 -0
- data/test/fixtures/organizations/retrieve.json +11 -0
- data/test/fixtures/outgoing_communications/list.json +24 -0
- data/test/fixtures/outgoing_communications/list_page2.json +21 -0
- data/test/fixtures/routing_forms/list_page2.json +17 -0
- data/test/fixtures/routing_forms/list_routing_form_submission_page2.json +29 -0
- data/test/fixtures/scheduling_links/create.json +7 -0
- data/test/fixtures/user_availability_schedules/list_page1.json +16 -0
- data/test/fixtures/user_availability_schedules/list_page2.json +16 -0
- data/test/fixtures/user_busy_times/list_page1.json +18 -0
- data/test/fixtures/user_busy_times/list_page2.json +13 -0
- data/test/fixtures/webhooks/list_page2.json +23 -0
- data/test/fixtures/webhooks/sample.json +66 -0
- data/test/test_helper.rb +10 -0
- metadata +64 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca7216a6bc050ebad873636af0bb988c8841d7828fe6cebc0a0497947c0a9dc7
|
|
4
|
+
data.tar.gz: e36f58a64ad9277fdd38bb44fe69aeb4e7d84fe10fb6b9274a474bb609406340
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 36c382f6725f7fdc22acfd11bee564dbcd5c448df265f49d07c450e074ab23c3a1f165970e4f5f925feebbcfbd7f3dae827ecc144a5ca0fb0c0524f9dcaa2d3c
|
|
7
|
+
data.tar.gz: 2e60e92afb872bb9590cda26e3208ed1bed7f069ea644a55738c5c6284447241c0c90358ff2a19d1e3c1149a790db2e69648c8ed945cd9ed6e4a9ed36526d575
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.0]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
* Auto-pagination via `Enumerator::Lazy` — `collection.auto_paginate` returns a lazy enumerator that traverses all pages on demand without pre-fetching. Compose with `.take(n)`, `.select { }`, `.map { }`, etc.
|
|
9
|
+
* `#next_page` method on `Collection` — returns the next page as a new `Collection`, or `nil` when there are no more pages.
|
|
10
|
+
* `#next_page_url` attr_reader on `Collection` — exposes the raw next-page URL string.
|
|
11
|
+
* `list_all` convenience methods on every resource with list endpoints:
|
|
12
|
+
- `client.events.list_all`, `client.events.list_all_invitees`
|
|
13
|
+
- `client.event_types.list_all`, `client.event_types.list_all_availability_schedules`, `client.event_types.list_all_memberships`
|
|
14
|
+
- `client.organizations.list_all_memberships`, `client.organizations.list_all_invitations`, `client.organizations.list_all_activity_log`
|
|
15
|
+
- `client.groups.list_all`, `client.groups.list_all_relationships`
|
|
16
|
+
- `client.availability.list_all_user_busy_times`, `client.availability.list_all_user_schedules`
|
|
17
|
+
- `client.routing_forms.list_all`, `client.routing_forms.list_all_submissions`
|
|
18
|
+
- `client.webhooks.list_all`
|
|
19
|
+
- `client.locations.list_all`
|
|
20
|
+
- `client.outgoing_communications.list_all`
|
|
21
|
+
* `GET /event_type_available_times` — `client.event_types.list_available_times(event_type:, start_time:, end_time:)` returns a `Collection` of `EventTypes::AvailableTime` objects. No pagination (not supported by this endpoint).
|
|
22
|
+
* `GET /event_type_memberships` — `client.event_types.list_memberships(event_type:)` and `list_all_memberships`. Returns `EventTypes::Membership` objects.
|
|
23
|
+
* `POST /scheduling_links` — `client.scheduling_links.create(owner:, owner_type:, max_event_count:)` returns a `SchedulingLink` object. Bare UUID expansion for `owner`.
|
|
24
|
+
* `GET /organizations/{uuid}` — `client.organizations.retrieve(uuid:)` returns an `Organization` object.
|
|
25
|
+
* `GET /outgoing_communications` — `client.outgoing_communications.list(organization:)` and `list_all`. Returns `OutgoingCommunication` objects.
|
|
26
|
+
* `GET /sample_webhook_data` — `client.webhooks.sample(event:, organization:, scope:)` returns the raw response hash (shape varies by event type).
|
|
27
|
+
|
|
28
|
+
### Changed — Breaking
|
|
29
|
+
* **`Collection#next_page`** (attr_reader returning the raw URL string) is now **`Collection#next_page_url`**. If you were reading the raw next-page URL via `collection.next_page`, change to `collection.next_page_url`.
|
|
30
|
+
* **`Collection#next_page`** is now a **method** that returns the next `Collection` object (or `nil`), not the raw URL string.
|
|
31
|
+
|
|
32
|
+
### Notes
|
|
33
|
+
* Version 1.0.0 signals complete Calendly API v2 coverage. All documented endpoints are now implemented.
|
|
34
|
+
* Changes originally prepared for an unreleased `0.11.0` were shipped as part of `1.0.0`.
|
|
35
|
+
|
|
36
|
+
[1.0.0]: https://github.com/araluce/calendlyr/compare/v0.10.0...v1.0.0
|
|
37
|
+
|
|
5
38
|
## [0.10.0]
|
|
6
39
|
|
|
7
40
|
### Added
|
|
41
|
+
* `Calendlyr::Webhook.verify!`, `valid?`, and `parse` — verify signed webhook payloads with HMAC-SHA256, optional timestamp tolerance, and typed payload parsing
|
|
42
|
+
* `Calendlyr.configure`, `Calendlyr.configuration`, `Calendlyr.client`, and `Calendlyr.reset!` — module-level global configuration and default client support with token/timeout settings
|
|
43
|
+
* Optional request/response logging via `Client.new(logger:)` or `Calendlyr.configure { |c| c.logger = ... }` — INFO for method/URL/status/duration, DEBUG for response body (truncated), WARN for retries, ERROR for API errors. Authorization header is never logged.
|
|
44
|
+
* `Object#to_json` — Serialize any API object to JSON. Works with `JSON.generate`, nested objects, and arrays. The internal `client` reference is automatically excluded from serialization.
|
|
8
45
|
* `client.data_compliance.delete_scheduled_event_data` — Remove scheduled events data within a time range (`POST /data_compliance/deletion/events`)
|
|
9
46
|
* `put_request` support in `Resource` base class for PUT HTTP verb
|
|
10
47
|
* `Collection` now includes `Enumerable` — use `each`, `map`, `select` directly on collections
|
|
@@ -17,6 +54,7 @@ All notable changes to this project will be documented in this file.
|
|
|
17
54
|
* Requires Ruby >= 3.2.0 (dropped support for Ruby 2.4–3.1)
|
|
18
55
|
|
|
19
56
|
### Fixed
|
|
57
|
+
* Error messages now include request context (`GET /path`) and expose structured attributes on `Calendlyr::Error` (`status`, `http_method`, `path`, `response_body`) for easier debugging
|
|
20
58
|
* **Security:** Removed `OpenSSL::SSL::VERIFY_NONE` — SSL connections now properly verify certificates
|
|
21
59
|
* **Security:** Bare `rescue` replaced with `rescue JSON::ParserError` — non-JSON errors are no longer silently swallowed
|
|
22
60
|
* `Invitee#cancel` now correctly uses the event UUID instead of the invitee UUID
|
data/README.md
CHANGED
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
# Calendlyr
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
The simplest way to interact with [Calendly's API v2](https://developer.calendly.com/api-docs) in Ruby. No runtime dependencies, no ceremony — just a Personal Access Token and you're good to go.
|
|
9
11
|
|
|
10
12
|
## Installation
|
|
11
13
|
|
|
14
|
+
Calendlyr requires **Ruby >= 3.2.0**.
|
|
15
|
+
|
|
12
16
|
Add to your Gemfile:
|
|
13
17
|
|
|
14
18
|
```ruby
|
|
@@ -22,8 +26,8 @@ Then run `bundle install`. That's it.
|
|
|
22
26
|
```ruby
|
|
23
27
|
client = Calendlyr::Client.new(token: ENV["CALENDLY_TOKEN"])
|
|
24
28
|
|
|
25
|
-
# List your scheduled events
|
|
26
|
-
events = client.events.list(user: "
|
|
29
|
+
# List your scheduled events — just pass the UUID, no full URI needed
|
|
30
|
+
events = client.events.list(user: "YOUR_USER_UUID")
|
|
27
31
|
events.data
|
|
28
32
|
#=> [#<Calendlyr::Event>, #<Calendlyr::Event>, ...]
|
|
29
33
|
|
|
@@ -38,15 +42,195 @@ invitees = client.events.list_invitees(uuid: event.uuid)
|
|
|
38
42
|
invitees.data.first.email #=> "john@example.com"
|
|
39
43
|
```
|
|
40
44
|
|
|
45
|
+
## Global configuration
|
|
46
|
+
|
|
47
|
+
For single-tenant apps, you can configure `Calendlyr` once and reuse a default client:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
Calendlyr.configure do |config|
|
|
51
|
+
config.token = ENV.fetch("CALENDLY_TOKEN")
|
|
52
|
+
config.open_timeout = 5
|
|
53
|
+
config.read_timeout = 15
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
client = Calendlyr.client
|
|
57
|
+
events = client.events.list(user: "YOUR_USER_UUID")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`Calendlyr.client` memoizes a client instance and rebuilds it if token or timeout values change.
|
|
61
|
+
|
|
62
|
+
### Optional request/response logging
|
|
63
|
+
|
|
64
|
+
Calendlyr can emit request lifecycle logs with any logger-like object that responds to `info`, `debug`, `warn`, and `error`. Logging is opt-in, and the gem does not ship a logger implementation for you.
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
require "logger"
|
|
68
|
+
|
|
69
|
+
client = Calendlyr::Client.new(token: ENV["CALENDLY_TOKEN"], logger: Logger.new($stdout))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`Logger` is just an example. You can pass any object that responds to `info`, `debug`, `warn`, and `error`.
|
|
73
|
+
|
|
74
|
+
If you're on Ruby 4 and want to use Ruby's `Logger`, make sure your application includes the `logger` gem.
|
|
75
|
+
|
|
76
|
+
Or configure it globally:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
Calendlyr.configure do |config|
|
|
80
|
+
config.token = ENV.fetch("CALENDLY_TOKEN")
|
|
81
|
+
config.logger = Logger.new($stdout)
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
In Rails, this is typically configured in an initializer:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# config/initializers/calendlyr.rb
|
|
89
|
+
Calendlyr.configure do |config|
|
|
90
|
+
config.token = ENV.fetch("CALENDLY_TOKEN")
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> [!IMPORTANT]
|
|
95
|
+
> `Calendlyr.client` is module-global and **not thread-safe for multi-tenant usage**.
|
|
96
|
+
> If your app serves multiple tenants or uses per-request credentials, use `Calendlyr::Client.new(token:)` per request.
|
|
97
|
+
|
|
98
|
+
### Bare UUIDs
|
|
99
|
+
|
|
100
|
+
Most methods that take a Calendly resource reference (like `user:`, `organization:`, `event_type:`, or `owner:`) accept both bare UUIDs and full URIs. When supported, the gem expands bare UUIDs automatically:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
# Both are equivalent:
|
|
104
|
+
client.events.list(user: "YOUR_USER_UUID")
|
|
105
|
+
client.events.list(user: "https://api.calendly.com/users/YOUR_USER_UUID")
|
|
106
|
+
```
|
|
107
|
+
|
|
41
108
|
The gem mirrors the Calendly API closely, so converting API examples into gem code is straightforward. Responses are wrapped in Ruby objects with dot-access for every field.
|
|
42
109
|
|
|
110
|
+
> **Note:** A few endpoints still expect a full Calendly URI for specific parameters. When that matters, the resource docs call it out explicitly.
|
|
111
|
+
|
|
112
|
+
### Webhook signature verification
|
|
113
|
+
|
|
114
|
+
`Calendlyr::Webhook` (singular) verifies signed webhook payloads. This is separate from `client.webhooks` / `Calendlyr::Webhooks` (plural), which are API resources for managing webhook subscriptions.
|
|
115
|
+
|
|
116
|
+
- Calendly sends the signature in the `Calendly-Webhook-Signature` HTTP header.
|
|
117
|
+
- In Rack/Rails, that header is available as `HTTP_CALENDLY_WEBHOOK_SIGNATURE`.
|
|
118
|
+
- `verify!` raises on invalid signature/timestamp; `valid?` returns `true`/`false`; `parse` verifies first, then JSON-parses and wraps the payload.
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
payload = request.body.read
|
|
122
|
+
signature_header = request.get_header("HTTP_CALENDLY_WEBHOOK_SIGNATURE")
|
|
123
|
+
signing_key = ENV.fetch("CALENDLY_WEBHOOK_SIGNING_KEY")
|
|
124
|
+
|
|
125
|
+
if Calendlyr::Webhook.valid?(payload: payload, signature_header: signature_header, signing_key: signing_key)
|
|
126
|
+
webhook = Calendlyr::Webhook.parse(
|
|
127
|
+
payload: payload,
|
|
128
|
+
signature_header: signature_header,
|
|
129
|
+
signing_key: signing_key
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
webhook.event #=> "invitee.created"
|
|
133
|
+
webhook.payload #=> Calendlyr::Webhooks::InviteePayload (for invitee.* events)
|
|
134
|
+
#=> Calendlyr::Object (for other/unknown events)
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### JSON serialization
|
|
139
|
+
|
|
140
|
+
All API objects support `#to_json` for easy serialization (caching, logging, API proxying):
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
event = client.events.retrieve(uuid: "ABC123")
|
|
144
|
+
|
|
145
|
+
event.to_json
|
|
146
|
+
#=> '{"uri":"https://api.calendly.com/scheduled_events/ABC123","name":"30 Minute Meeting",...}'
|
|
147
|
+
|
|
148
|
+
# Works with JSON.generate and nested objects
|
|
149
|
+
JSON.generate(event)
|
|
150
|
+
|
|
151
|
+
# Round-trip: parse back into an Object
|
|
152
|
+
parsed = Calendlyr::Object.new(JSON.parse(event.to_json))
|
|
153
|
+
parsed.name #=> "30 Minute Meeting"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> **Note:** `#to_json` and `#to_h` exclude the internal `client` reference — only API data is serialized.
|
|
157
|
+
|
|
158
|
+
### Error context
|
|
159
|
+
|
|
160
|
+
API errors now include the HTTP method and path in the message, and expose structured attributes for debugging:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
begin
|
|
164
|
+
client.events.retrieve(uuid: "INVALID_UUID")
|
|
165
|
+
rescue Calendlyr::NotFound => error
|
|
166
|
+
error.message #=> "[Error 404] GET /scheduled_events/INVALID_UUID — Not Found. The resource you requested does not exist."
|
|
167
|
+
error.status #=> 404
|
|
168
|
+
error.http_method #=> "GET"
|
|
169
|
+
error.path #=> "/scheduled_events/INVALID_UUID"
|
|
170
|
+
error.response_body #=> { "title" => "Not Found", "message" => "..." }
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This makes debugging failed requests much easier without changing existing `rescue Calendlyr::Error` patterns.
|
|
175
|
+
|
|
176
|
+
## Auto-pagination
|
|
177
|
+
|
|
178
|
+
Calendlyr supports lazy auto-pagination for paginated collection endpoints. There are two ways to consume paginated results:
|
|
179
|
+
|
|
180
|
+
### `list_all` — Eager, returns a flat Array
|
|
181
|
+
|
|
182
|
+
The simplest option. Fetches every page and returns all items as an Array.
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# Get all events across all pages (e.g., hundreds of events)
|
|
186
|
+
events = client.events.list_all(organization: "YOUR_ORG_UUID")
|
|
187
|
+
events #=> [#<Calendlyr::Event>, #<Calendlyr::Event>, ...]
|
|
188
|
+
|
|
189
|
+
# Same pattern works for every resource with a list method:
|
|
190
|
+
client.event_types.list_all(organization: "YOUR_ORG_UUID")
|
|
191
|
+
client.webhooks.list_all(organization: "YOUR_ORG_UUID", scope: "organization")
|
|
192
|
+
client.organizations.list_all_memberships(organization: "YOUR_ORG_UUID")
|
|
193
|
+
client.organizations.list_all_invitations(uuid: "YOUR_ORG_UUID")
|
|
194
|
+
client.organizations.list_all_activity_log(organization: "YOUR_ORG_UUID")
|
|
195
|
+
client.groups.list_all(organization: "YOUR_ORG_UUID")
|
|
196
|
+
client.groups.list_all_relationships(organization: "YOUR_ORG_UUID")
|
|
197
|
+
client.routing_forms.list_all(organization: "YOUR_ORG_UUID")
|
|
198
|
+
client.routing_forms.list_all_submissions(form: "YOUR_FORM_UUID")
|
|
199
|
+
client.availability.list_all_user_busy_times(user: "YOUR_USER_UUID", start_time: "...", end_time: "...")
|
|
200
|
+
client.availability.list_all_user_schedules(user: "YOUR_USER_UUID")
|
|
201
|
+
client.locations.list_all
|
|
202
|
+
client.event_types.list_all_memberships(event_type: "YOUR_EVENT_TYPE_UUID")
|
|
203
|
+
client.outgoing_communications.list_all(organization: "YOUR_ORG_UUID")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `auto_paginate` — Lazy Enumerator
|
|
207
|
+
|
|
208
|
+
Returns an `Enumerator::Lazy` that fetches pages on demand. Pages are only requested as you consume items, so you can stop early without fetching all pages.
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
collection = client.events.list(organization: "YOUR_ORG_UUID")
|
|
212
|
+
|
|
213
|
+
# Take only the first 50 events — fetches only as many pages as needed
|
|
214
|
+
first_50 = collection.auto_paginate.take(50)
|
|
215
|
+
|
|
216
|
+
# Filter lazily — stops fetching once the condition is met
|
|
217
|
+
active = collection.auto_paginate.select { |e| e.status == "active" }.first(10)
|
|
218
|
+
|
|
219
|
+
# Consume all items lazily
|
|
220
|
+
collection.auto_paginate.each do |event|
|
|
221
|
+
puts event.name
|
|
222
|
+
end
|
|
223
|
+
```
|
|
224
|
+
|
|
43
225
|
## Documentation
|
|
44
226
|
|
|
45
227
|
For the full list of available resources and methods, check out the [API Reference](docs/resources/).
|
|
46
228
|
|
|
229
|
+
The docs in this repository focus on the Ruby wrapper API. For request/response schemas and endpoint-level behavior, use the official Calendly API docs linked from each resource page.
|
|
230
|
+
|
|
47
231
|
## Contributing
|
|
48
232
|
|
|
49
|
-
1. Fork it
|
|
233
|
+
1. [Fork it](https://github.com/araluce/calendlyr/fork)
|
|
50
234
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
51
235
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
52
236
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/calendlyr.gemspec
CHANGED
|
@@ -7,16 +7,19 @@ Gem::Specification.new do |spec|
|
|
|
7
7
|
spec.email = ["araluce11@gmail.com"]
|
|
8
8
|
|
|
9
9
|
spec.summary = "Ruby bindings for Calendly API."
|
|
10
|
-
spec.description = "Ruby bindings for Calendly API.
|
|
10
|
+
spec.description = "Ruby bindings for Calendly API v2. Full docs: https://developer.calendly.com/api-docs/"
|
|
11
11
|
spec.homepage = "https://github.com/araluce/calendlyr"
|
|
12
12
|
spec.license = "MIT"
|
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
|
|
14
14
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
15
|
+
spec.metadata["changelog_uri"] = "https://github.com/araluce/calendlyr/blob/master/CHANGELOG.md"
|
|
16
|
+
spec.metadata["documentation_uri"] = "https://github.com/araluce/calendlyr/tree/master/docs"
|
|
15
17
|
|
|
16
18
|
spec.files = `git ls-files -z`.split("\x0")
|
|
17
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
20
|
spec.require_paths = ["lib"]
|
|
19
21
|
|
|
22
|
+
spec.add_development_dependency "logger", "~> 1.6"
|
|
20
23
|
spec.add_development_dependency "minitest", "~> 5.25"
|
|
21
24
|
spec.add_development_dependency "rake", "~> 13.2"
|
|
22
25
|
spec.add_development_dependency "simplecov", "~> 0.21"
|
|
@@ -13,7 +13,8 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/d37c7f031f339-l
|
|
|
13
13
|
For the example bellow we will use only required parameters, but you can use any other parameter as well.
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
|
-
|
|
16
|
+
# organization: accepts a bare UUID or full Calendly URI
|
|
17
|
+
client.organizations.activity_log(organization: "ORG_UUID")
|
|
17
18
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::ActivityLog, ...], @client=#<Calendlyr::Client>>
|
|
18
19
|
```
|
|
19
20
|
|
|
@@ -20,8 +20,9 @@ client.availabilities.retrieve_user_schedule(uuid: @uuid)
|
|
|
20
20
|
Return the availability schedules of the given user. See [official API doc](https://developer.calendly.com/api-docs/8098de44af94c-list-user-availability-schedules)
|
|
21
21
|
|
|
22
22
|
```ruby
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
# user: accepts a bare UUID or full Calendly URI
|
|
24
|
+
client.availabilities.list_user_schedules(user: "USER_UUID")
|
|
25
|
+
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Availabilities::UserSchedule>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
#### List on me
|
|
@@ -14,8 +14,9 @@ Date range can be no greater than 1 week (7 days).
|
|
|
14
14
|
|
|
15
15
|
For the example bellow we will use only required parameters, but you can use any other parameter as well.
|
|
16
16
|
```ruby
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
# user: accepts a bare UUID or full Calendly URI
|
|
18
|
+
client.availabilities.list_user_busy_times(user: "USER_UUID", start_time: start_time, end_time: end_time)
|
|
19
|
+
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Availabilities::UserBusyTime>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
## Object methods
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Available Time (`Calendlyr::EventTypes::AvailableTime`)
|
|
2
|
+
|
|
3
|
+
Available time for a specific Event Type in a given time window.
|
|
4
|
+
|
|
5
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
6
|
+
|
|
7
|
+
## Client requests
|
|
8
|
+
|
|
9
|
+
### List Available Times
|
|
10
|
+
|
|
11
|
+
Returns available time slots for an Event Type between `start_time` and `end_time`.
|
|
12
|
+
|
|
13
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# event_type: accepts a bare UUID or full Calendly URI
|
|
17
|
+
client.event_types.list_available_times(
|
|
18
|
+
event_type: "EVENT_TYPE_UUID",
|
|
19
|
+
start_time: "2026-04-07T09:00:00Z",
|
|
20
|
+
end_time: "2026-04-07T18:00:00Z"
|
|
21
|
+
)
|
|
22
|
+
#=> #<Calendlyr::Collection @data=[#<Calendlyr::EventTypes::AvailableTime>, ...], ...>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This endpoint does not support pagination.
|
|
@@ -24,10 +24,11 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/25a4ece03c1bc-l
|
|
|
24
24
|
|
|
25
25
|
For the examples bellow we will use only required parameters, but you can use any other parameter as well.
|
|
26
26
|
```ruby
|
|
27
|
-
|
|
27
|
+
# user: and organization: accept bare UUIDs or full Calendly URIs
|
|
28
|
+
client.event_types.list(user: "USER_UUID")
|
|
28
29
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::EventType>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
29
30
|
|
|
30
|
-
client.event_types.list(organization:
|
|
31
|
+
client.event_types.list(organization: "ORG_UUID")
|
|
31
32
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::EventType>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
32
33
|
```
|
|
33
34
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Event Type Membership (`Calendlyr::EventTypes::Membership`)
|
|
2
|
+
|
|
3
|
+
Membership object for an Event Type.
|
|
4
|
+
|
|
5
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
6
|
+
|
|
7
|
+
## Client requests
|
|
8
|
+
|
|
9
|
+
### List
|
|
10
|
+
|
|
11
|
+
Returns memberships for a specified Event Type.
|
|
12
|
+
|
|
13
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# event_type: accepts a bare UUID or full Calendly URI
|
|
17
|
+
client.event_types.list_memberships(event_type: "EVENT_TYPE_UUID")
|
|
18
|
+
#=> #<Calendlyr::Collection @data=[#<Calendlyr::EventTypes::Membership>, ...], ...>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### List All
|
|
22
|
+
|
|
23
|
+
Fetches every membership page and returns a flat Array.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
client.event_types.list_all_memberships(event_type: "EVENT_TYPE_UUID")
|
|
27
|
+
#=> [#<Calendlyr::EventTypes::Membership>, ...]
|
|
28
|
+
```
|
|
@@ -24,13 +24,14 @@ Returns a list of Events.
|
|
|
24
24
|
Visit official [API Doc](https://developer.calendly.com/api-docs/2d5ed9bbd2952-list-events)
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
|
|
27
|
+
# You can pass bare UUIDs or full Calendly URIs for user:, organization:, and group:
|
|
28
|
+
client.events.list(organization: "ORG_UUID", user: "USER_UUID")
|
|
28
29
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Event>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
29
30
|
|
|
30
|
-
client.events.list(organization:
|
|
31
|
+
client.events.list(organization: "ORG_UUID", group: group)
|
|
31
32
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Event>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
32
33
|
|
|
33
|
-
client.events.list(user:
|
|
34
|
+
client.events.list(user: "USER_UUID")
|
|
34
35
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Event>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
35
36
|
```
|
|
36
37
|
|
|
@@ -32,8 +32,9 @@ client.events.list_invitees(uuid: uuid)
|
|
|
32
32
|
Creates and schedules an Invitee.
|
|
33
33
|
|
|
34
34
|
```ruby
|
|
35
|
+
# event_type: accepts a bare UUID or full Calendly URI
|
|
35
36
|
client.events.create_invitee(
|
|
36
|
-
event_type:
|
|
37
|
+
event_type: "EVENT_TYPE_UUID",
|
|
37
38
|
start_time: "2019-08-07T06:05:04.321123Z",
|
|
38
39
|
invitee: {
|
|
39
40
|
name: "John Doe",
|
|
@@ -24,7 +24,8 @@ Marks an Invitee as a No Show.
|
|
|
24
24
|
Visit official [API Doc](https://developer.calendly.com/api-docs/cebd8c3170790-create-invitee-no-show)
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
|
|
27
|
+
# invitee: accepts a bare UUID or full Calendly URI
|
|
28
|
+
client.events.create_invitee_no_show(invitee: "INVITEE_UUID")
|
|
28
29
|
#=> #<Calendlyr::Events::InviteeNoShow>
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -24,7 +24,8 @@ Returns a list of groups.
|
|
|
24
24
|
Visit official [API Doc](https://developer.calendly.com/api-docs/6rb6dtdln74sy-list-groups)
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
|
|
27
|
+
# organization: accepts a bare UUID or full Calendly URI
|
|
28
|
+
client.groups.list(organization: "ORG_UUID")
|
|
28
29
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Group>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -26,10 +26,11 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/eaed2e61a6bc3-l
|
|
|
26
26
|
For the example bellow we will use only required parameters, but you can use any other parameter as well.
|
|
27
27
|
|
|
28
28
|
```ruby
|
|
29
|
-
|
|
29
|
+
# user: and organization: accept bare UUIDs or full Calendly URIs
|
|
30
|
+
client.organizations.list_memberships(user: "USER_UUID")
|
|
30
31
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Organizations::Membership>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
31
32
|
|
|
32
|
-
client.organizations.list_memberships(organization:
|
|
33
|
+
client.organizations.list_memberships(organization: "ORG_UUID")
|
|
33
34
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::Organizations::Membership>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
34
35
|
```
|
|
35
36
|
|
|
@@ -13,6 +13,19 @@ organization = client.organization
|
|
|
13
13
|
#=> #<Calendlyr::Organization>
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## Client requests
|
|
17
|
+
|
|
18
|
+
### Retrieve
|
|
19
|
+
|
|
20
|
+
Returns information about a specified Organization.
|
|
21
|
+
|
|
22
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
client.organizations.retrieve(uuid: "ORG_UUID")
|
|
26
|
+
#=> #<Calendlyr::Organization>
|
|
27
|
+
```
|
|
28
|
+
|
|
16
29
|
## Object methods
|
|
17
30
|
|
|
18
31
|
### Activity Logs
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Outgoing Communication (`Calendlyr::OutgoingCommunication`)
|
|
2
|
+
|
|
3
|
+
Outgoing communication object.
|
|
4
|
+
|
|
5
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
6
|
+
|
|
7
|
+
## Client requests
|
|
8
|
+
|
|
9
|
+
### List
|
|
10
|
+
|
|
11
|
+
Returns outgoing communications for a specified Organization.
|
|
12
|
+
|
|
13
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# organization: accepts a bare UUID or full Calendly URI
|
|
17
|
+
client.outgoing_communications.list(organization: "ORG_UUID")
|
|
18
|
+
#=> #<Calendlyr::Collection @data=[#<Calendlyr::OutgoingCommunication>, ...], ...>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### List All
|
|
22
|
+
|
|
23
|
+
Fetches every page and returns a flat Array.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
client.outgoing_communications.list_all(organization: "ORG_UUID")
|
|
27
|
+
#=> [#<Calendlyr::OutgoingCommunication>, ...]
|
|
28
|
+
```
|
|
@@ -26,7 +26,8 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/9fe7334bec6ad-l
|
|
|
26
26
|
For the example bellow we will use only required parameters, but you can use any other parameter as well.
|
|
27
27
|
|
|
28
28
|
```ruby
|
|
29
|
-
|
|
29
|
+
# organization: accepts a bare UUID or full Calendly URI
|
|
30
|
+
client.routing_forms.list(organization: "ORG_UUID")
|
|
30
31
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::RoutingForm>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
31
32
|
```
|
|
32
33
|
|
|
@@ -26,7 +26,8 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/17db5cb915a57-l
|
|
|
26
26
|
For the example bellow we will use only required parameters, but you can use any other parameter as well.
|
|
27
27
|
|
|
28
28
|
```ruby
|
|
29
|
-
|
|
29
|
+
# form: accepts a bare UUID or full Calendly URI
|
|
30
|
+
client.routing_forms.list_submissions(form: "ROUTING_FORM_UUID")
|
|
30
31
|
#=> #<Calendlyr::Collection @data=[#<Calendlyr::RoutingForms::Submission>, ...], @count=nil, @next_page=nil, @next_page_token=nil, @client=#<Calendlyr::Client>>
|
|
31
32
|
```
|
|
32
33
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Scheduling Link (`Calendlyr::SchedulingLink`)
|
|
2
|
+
|
|
3
|
+
Scheduling link object.
|
|
4
|
+
|
|
5
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
6
|
+
|
|
7
|
+
## Client requests
|
|
8
|
+
|
|
9
|
+
### Create
|
|
10
|
+
|
|
11
|
+
Creates a scheduling link for an Event Type owner.
|
|
12
|
+
|
|
13
|
+
Visit official [API Doc](https://developer.calendly.com/api-docs)
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# owner: accepts a bare UUID or full Calendly URI
|
|
17
|
+
client.scheduling_links.create(owner: "EVENT_TYPE_UUID")
|
|
18
|
+
#=> #<Calendlyr::SchedulingLink>
|
|
19
|
+
|
|
20
|
+
client.scheduling_links.create(
|
|
21
|
+
owner: "EVENT_TYPE_UUID",
|
|
22
|
+
owner_type: "EventType",
|
|
23
|
+
max_event_count: 3
|
|
24
|
+
)
|
|
25
|
+
#=> #<Calendlyr::SchedulingLink>
|
|
26
|
+
```
|
data/docs/resources/share.md
CHANGED
|
@@ -14,7 +14,8 @@ Endpoint for our Customize Once and Share feature. This allows you to customize
|
|
|
14
14
|
Visit official [API Doc](https://developer.calendly.com/api-docs/fdcac06abfc8c-create-share)
|
|
15
15
|
|
|
16
16
|
```ruby
|
|
17
|
-
|
|
17
|
+
# event_type: accepts a bare UUID or full Calendly URI
|
|
18
|
+
client.shares.create(event_type: "EVENT_TYPE_UUID", name: "15 minute meeting", duration: ...)
|
|
18
19
|
#=> #<Calendlyr::Share>
|
|
19
20
|
```
|
|
20
21
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
# Webhooks Invitee Payload Calendlyr::
|
|
1
|
+
# Webhooks Invitee Payload (`Calendlyr::Webhooks::InviteePayload`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed payload wrapper used by `Calendlyr::Webhook.parse` when `event` is one of:
|
|
4
|
+
- `invitee.created`
|
|
5
|
+
- `invitee.canceled`
|
|
6
|
+
- `invitee_no_show.created`
|
|
7
|
+
- `invitee_no_show.deleted`
|
|
8
|
+
|
|
9
|
+
For other events, `parsed.payload` is returned as a generic `Calendlyr::Object`.
|
|
4
10
|
|
|
5
11
|
Visit official [API Doc](https://developer.calendly.com/api-docs/b92768854bc06-invitee-payload)
|
|
6
12
|
|
|
@@ -9,7 +15,7 @@ Visit official [API Doc](https://developer.calendly.com/api-docs/b92768854bc06-i
|
|
|
9
15
|
### Associated Event
|
|
10
16
|
|
|
11
17
|
```ruby
|
|
12
|
-
webhook_invitee_payload.
|
|
18
|
+
webhook_invitee_payload.associated_event
|
|
13
19
|
#=> #<Calendlyr::Event>
|
|
14
20
|
```
|
|
15
21
|
|
|
@@ -27,16 +33,4 @@ webhook_invitee_payload.associated_invitee_no_show
|
|
|
27
33
|
#=> #<Calendlyr::Events::InviteeNoShow>
|
|
28
34
|
```
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
webhook_subscription.active?
|
|
34
|
-
#=> true
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### disabled?
|
|
38
|
-
|
|
39
|
-
```ruby
|
|
40
|
-
webhook_subscription.disabled?
|
|
41
|
-
#=> false
|
|
42
|
-
```
|
|
36
|
+
`active?` / `disabled?` are methods on `Calendlyr::Webhooks::Subscription`, not on invitee payloads.
|