Quick start •
+ Migrate from v2 •
Why intercom-go? •
Examples •
API coverage •
@@ -85,6 +86,14 @@ client options:
client, err := intercom.NewClient("access-token", intercom.WithRegion(intercom.EU))
```
+## Migrating from the legacy v2 client
+
+`intercom-go` is an independent, community-maintained SDK rather than a drop-in
+replacement for `gopkg.in/intercom/intercom-go.v2`. It uses the current Intercom
+API model and requires a `context.Context` on each service call. The
+[migration guide](docs/migrating-from-intercom-go-v2.md) maps common workflows
+and calls out the deliberate API differences.
+
## Everyday API
### Retrieve and search contacts
@@ -229,6 +238,9 @@ internal under [`internal/generated/intercom`](internal/generated/intercom).
- [`examples/identify_admin`](examples/identify_admin)
- [`examples/search_contacts`](examples/search_contacts)
+- [`examples/list_conversations`](examples/list_conversations)
+- [`examples/observe_rate_limits`](examples/observe_rate_limits)
+- [`examples/verify_webhook`](examples/verify_webhook)
## Support and Security
diff --git a/docs/assets/social-preview-background.png b/docs/assets/social-preview-background.png
new file mode 100644
index 0000000..265c319
Binary files /dev/null and b/docs/assets/social-preview-background.png differ
diff --git a/docs/assets/social-preview-overlay.svg b/docs/assets/social-preview-overlay.svg
new file mode 100644
index 0000000..5eab831
--- /dev/null
+++ b/docs/assets/social-preview-overlay.svg
@@ -0,0 +1,20 @@
+
diff --git a/docs/assets/social-preview.png b/docs/assets/social-preview.png
new file mode 100644
index 0000000..97a2b3e
Binary files /dev/null and b/docs/assets/social-preview.png differ
diff --git a/docs/launch-checklist.md b/docs/launch-checklist.md
new file mode 100644
index 0000000..a69878d
--- /dev/null
+++ b/docs/launch-checklist.md
@@ -0,0 +1,75 @@
+# Launch Checklist
+
+This checklist prepares the public `v0.2.2` release and retains the proposed
+community announcements for explicit approval. Do not submit either draft
+without approval of its final text, target, links, and account identity.
+
+## Repository settings
+
+- [x] Repository description: `Modern, production-ready Go SDK for Intercom API 2.15 (unofficial, community-maintained).`
+- [x] Homepage:
+- [x] Topics: `api-client`, `go`, `golang`, `intercom`, `intercom-api`, `openapi`, `sdk`.
+- [ ] Upload [`docs/assets/social-preview.png`](assets/social-preview.png), a 1280×640 PNG under 1 MB, in GitHub's **Settings → General → Social preview**.
+
+## Release checks
+
+- [x] Run `make pre-push`.
+- [ ] Merge the release-preparation pull request into `main`.
+- [ ] Publish immutable tag and GitHub release `v0.2.2`.
+- [ ] Verify `GOPROXY=proxy.golang.org go list -m github.com/uffejaeger/intercom-go@v0.2.2`.
+- [ ] Verify shows `v0.2.2`.
+
+Installation command:
+
+```sh
+go get github.com/uffejaeger/intercom-go@v0.2.2
+```
+
+Release summary:
+
+> v0.2.2 adds a migration guide from the legacy v2 client and runnable examples
+> for verified webhooks, conversation iteration, and response/rate-limit
+> observability. It makes no public Go API changes.
+
+## Draft: Go Forum Releases
+
+**Title:** `intercom-go v0.2.2 — a community-maintained Go SDK for Intercom API 2.15`
+
+> I released `intercom-go` v0.2.2, an unofficial, community-maintained Go SDK
+> for Intercom API 2.15.
+>
+> It keeps generated OpenAPI code internal while exposing idiomatic services,
+> opt-in conservative retries, regional endpoints, request/rate-limit metadata,
+> verified webhooks, and local HTTP test support.
+>
+> Install: `go get github.com/uffejaeger/intercom-go@v0.2.2`
+>
+> The release includes a migration guide for
+> `gopkg.in/intercom/intercom-go.v2` and runnable webhook, conversation, and
+> observability examples:
+>
+> I would especially value feedback from teams replacing the legacy client:
+> which workflow or migration helper would make evaluation easier?
+
+## Draft: Intercom Community
+
+**Title:** `Community Go SDK for Intercom API 2.15 — looking for migration feedback`
+
+> I maintain `intercom-go`, an unofficial, community-maintained Go SDK for
+> Intercom API 2.15. It is not affiliated with or endorsed by Intercom.
+>
+> The project offers typed services, optional conservative retries, regional
+> endpoints, response/rate-limit metadata, verified webhooks, and local HTTP
+> test support. The latest release also includes a migration guide for the
+> legacy `gopkg.in/intercom/intercom-go.v2` client:
+>
+>
+> If you are using Go with Intercom, which legacy-client workflow would you
+> want documented or supported first?
+
+## Approval gate
+
+Before posting either draft, confirm the exact final text, destination URL,
+account identity, and every linked page with the repository owner. Do not
+cross-post or submit to newsletters, curated lists, Reddit, or Intercom
+documentation without separate approval.
diff --git a/docs/migrating-from-intercom-go-v2.md b/docs/migrating-from-intercom-go-v2.md
new file mode 100644
index 0000000..1c922b7
--- /dev/null
+++ b/docs/migrating-from-intercom-go-v2.md
@@ -0,0 +1,116 @@
+# Migrating From `intercom-go.v2`
+
+This SDK is an independent, community-maintained alternative to
+[`gopkg.in/intercom/intercom-go.v2`](https://github.com/intercom/intercom-go).
+It is not a drop-in replacement: its public API is shaped around the current
+Intercom API and requires a `context.Context` for every request.
+
+Start a migration on a branch, upgrade one workflow at a time, and retain the
+legacy client until its replacement has been exercised against a test
+workspace. Never run both clients with the same request path in production
+unless the operation is safe to duplicate.
+
+## Install and construct a client
+
+Replace the legacy module:
+
+```sh
+go get github.com/uffejaeger/intercom-go@v0.2.2
+```
+
+```go
+// Before
+import intercom "gopkg.in/intercom/intercom-go.v2"
+
+legacy := intercom.NewClient("access-token", "")
+
+// After
+import intercom "github.com/uffejaeger/intercom-go"
+
+client, err := intercom.NewClient("access-token")
+if err != nil {
+ return err
+}
+```
+
+For applications that already keep credentials in the environment, use
+`intercom.NewClientFromEnv()`. Select a non-US Intercom region at construction
+time with `intercom.WithRegion(intercom.EU)` or `intercom.WithRegion(intercom.AU)`.
+
+## Add a context and deadline
+
+Legacy calls do not take a context. Give each replacement request a deadline
+that covers its expected work, including any retry waits:
+
+```go
+ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+defer cancel()
+
+contact, err := client.Contacts.Get(ctx, contactID)
+```
+
+## Map common contact workflows
+
+| Legacy v2 workflow | `intercom-go` workflow |
+| --- | --- |
+| `ic.Contacts.FindByID(id)` | `client.Contacts.Get(ctx, id)` |
+| `ic.Contacts.FindByUserID(id)` | `client.Contacts.GetByExternalID(ctx, id)` |
+| `ic.Contacts.ListByEmail(email, ...)` | `client.Contacts.Search(ctx, intercom.ContactSearch{Field: "email", Operator: intercom.ContactSearchEquals, Value: email})` |
+| `ic.Contacts.List(...)` | `client.Contacts.List(ctx)` for the first page, or `SearchIter` for cursor-paginated search results |
+| `ic.Contacts.Create(...)` | `client.Contacts.Create(ctx, intercom.ContactCreate{...})` |
+| `ic.Contacts.Update(...)` | `client.Contacts.Update(ctx, contactID, intercom.ContactUpdate{...})` |
+
+The older SDK distinguishes users and contacts in places where the current
+Intercom API uses contacts. Review each legacy user call against the current
+API before moving it; do not assume a mechanical method rename is correct.
+
+## Replace client options and HTTP tracing
+
+Pass options when constructing the client instead of calling `ic.Option` later:
+
+```go
+client, err := intercom.NewClient("access-token",
+ intercom.WithHTTPClient(http.DefaultClient),
+ intercom.WithRetry(intercom.RetryConfig{MaxAttempts: 3}),
+ intercom.WithResponseHook(func(info intercom.ResponseInfo) {
+ log.Printf("status=%d request_id=%s remaining=%s",
+ info.StatusCode, info.RequestID, info.RateLimitRemaining)
+ }),
+)
+```
+
+`WithResponseHook` is the replacement for ad-hoc transport tracing when the
+goal is observability. Keep hooks fast and never log access tokens, request
+bodies, or customer data.
+
+## Paginate conversations safely
+
+Use an iterator rather than manually retaining a cursor:
+
+```go
+iter := client.Conversations.ListIter(ctx, intercom.CursorPageOptions{PerPage: 25})
+for iter.Next() {
+ conversation := iter.Conversation()
+ // Process the item without logging customer data.
+ _ = conversation
+}
+if err := iter.Err(); err != nil {
+ return err
+}
+```
+
+The iterator stops with `intercom.ErrPaginationStalled` if Intercom repeats a
+cursor, preventing an accidental infinite loop.
+
+## Handle errors and webhooks
+
+Use `intercom.IsNotFound(err)` for missing resources and `errors.As` with
+`*intercom.ErrorResponse` when an application needs response status, headers,
+or Intercom's request ID. For webhooks, use `ParseAndVerifyWebhook` so the
+signature is checked against the exact request bytes before parsing.
+
+See the runnable [webhook](../examples/verify_webhook),
+[conversation](../examples/list_conversations), and
+[observability](../examples/observe_rate_limits) examples. Consult the
+[production guide](production.md) before enabling retries for an existing
+write path.
diff --git a/examples/list_conversations/main.go b/examples/list_conversations/main.go
new file mode 100644
index 0000000..c8ea6ac
--- /dev/null
+++ b/examples/list_conversations/main.go
@@ -0,0 +1,33 @@
+// list_conversations lists conversation pages lazily without retaining cursors.
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "time"
+
+ intercom "github.com/uffejaeger/intercom-go"
+)
+
+func main() {
+ client, err := intercom.NewClientFromEnv()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+ defer cancel()
+
+ iter := client.Conversations.ListIter(ctx, intercom.CursorPageOptions{PerPage: 25})
+ count := 0
+ for iter.Next() {
+ // Process the conversation here. Avoid logging customer data by default.
+ count++
+ }
+ if err := iter.Err(); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("processed %d conversations\n", count)
+}
diff --git a/examples/observe_rate_limits/main.go b/examples/observe_rate_limits/main.go
new file mode 100644
index 0000000..cb9ed1a
--- /dev/null
+++ b/examples/observe_rate_limits/main.go
@@ -0,0 +1,32 @@
+// observe_rate_limits records request metadata without logging credentials or payloads.
+package main
+
+import (
+ "context"
+ "log"
+
+ intercom "github.com/uffejaeger/intercom-go"
+)
+
+func main() {
+ client, err := intercom.NewClientFromEnv(
+ intercom.WithResponseHook(func(info intercom.ResponseInfo) {
+ log.Printf("attempt=%d/%d status=%d request_id=%s remaining=%s reset=%s duration=%s",
+ info.Attempt,
+ info.MaxAttempts,
+ info.StatusCode,
+ info.RequestID,
+ info.RateLimitRemaining,
+ info.RateLimitReset,
+ info.Duration,
+ )
+ }),
+ )
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if _, err := client.Admins.Me(context.Background()); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/examples/verify_webhook/main.go b/examples/verify_webhook/main.go
new file mode 100644
index 0000000..28709b9
--- /dev/null
+++ b/examples/verify_webhook/main.go
@@ -0,0 +1,43 @@
+// verify_webhook runs a minimal HTTP endpoint that verifies Intercom webhooks
+// before processing their payloads.
+package main
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+
+ intercom "github.com/uffejaeger/intercom-go"
+)
+
+func main() {
+ clientSecret := os.Getenv("INTERCOM_CLIENT_SECRET")
+ if clientSecret == "" {
+ log.Fatal("INTERCOM_CLIENT_SECRET is required")
+ }
+
+ http.HandleFunc("/webhooks/intercom", func(w http.ResponseWriter, r *http.Request) {
+ event, err := intercom.ParseAndVerifyWebhook(r, clientSecret, 0)
+ if err != nil {
+ switch {
+ case errors.Is(err, intercom.ErrWebhookPayloadTooLarge):
+ http.Error(w, "payload too large", http.StatusRequestEntityTooLarge)
+ case errors.Is(err, intercom.ErrWebhookSignatureMissing),
+ errors.Is(err, intercom.ErrWebhookSignatureInvalid),
+ errors.Is(err, intercom.ErrWebhookSignatureUnsupported):
+ http.Error(w, "invalid webhook signature", http.StatusUnauthorized)
+ default:
+ http.Error(w, "invalid webhook", http.StatusBadRequest)
+ }
+ return
+ }
+
+ // Decode event.Data.Item only for topics this endpoint handles.
+ log.Printf("verified webhook topic=%s id=%s", event.Topic, event.ID)
+ fmt.Fprintln(w, "ok")
+ })
+
+ log.Fatal(http.ListenAndServe(":8080", nil))
+}