# Intercom Client

Manage customer conversations, contacts, and support workflows with Intercom.

## Methods

| Method                                   | Description                                          |
| ---------------------------------------- | ---------------------------------------------------- |
| `apiRequest(options, schema, metadata?)` | Make any Intercom API request with schema validation |

## Usage

### Create or Update a Contact

```typescript
import { api, z, intercom } from "@superblocksteam/sdk-api";

// Integration ID from the integrations panel
const PROD_INTERCOM = "a1b2c3d4-5678-90ab-cdef-intercom0001";

const ContactResponseSchema = z.object({
  type: z.literal("contact"),
  id: z.string(),
  external_id: z.string().nullable(),
  email: z.string().nullable(),
  name: z.string().nullable(),
  role: z.string(),
  created_at: z.number(),
  updated_at: z.number(),
  custom_attributes: z.record(z.unknown()),
});

export default api({
  integrations: {
    intercom: intercom(PROD_INTERCOM),
  },
  name: "IntercomExample",
  input: z.object({
    email: z.string().email(),
    name: z.string(),
  }),
  output: z.object({
    contactId: z.string(),
  }),
  async run(ctx, { email, name }) {
    const result = await ctx.integrations.intercom.apiRequest(
      {
        method: "POST",
        path: "/contacts",
        body: {
          role: "user",
          email: email,
          name: name,
        },
      },
      { response: ContactResponseSchema },
    );

    return { contactId: result.id };
  },
});
```

### Search Contacts

```typescript
const SearchResponseSchema = z.object({
  type: z.literal("list"),
  data: z.array(ContactResponseSchema),
  total_count: z.number(),
  pages: z.object({
    type: z.literal("pages"),
    page: z.number(),
    per_page: z.number(),
    total_pages: z.number(),
  }),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: "/contacts/search",
    body: {
      query: {
        field: "email",
        operator: "=",
        value: "user@example.com",
      },
    },
  },
  { response: SearchResponseSchema },
);

if (result.data.length > 0) {
  console.log(`Found contact: ${result.data[0].name}`);
}
```

### Send a Message

```typescript
const MessageResponseSchema = z.object({
  type: z.literal("admin_message"),
  id: z.string(),
  created_at: z.number(),
  body: z.string(),
  message_type: z.string(),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: "/messages",
    body: {
      message_type: "email",
      subject: "Welcome!",
      body: "Thanks for signing up!",
      from: {
        type: "admin",
        id: "123456", // Admin ID
      },
      to: {
        type: "user",
        email: "user@example.com",
      },
    },
  },
  { response: MessageResponseSchema },
);
```

### Create a Conversation

```typescript
const ConversationResponseSchema = z.object({
  type: z.literal("conversation"),
  id: z.string(),
  created_at: z.number(),
  updated_at: z.number(),
  title: z.string().nullable(),
  state: z.string(),
  source: z.object({
    type: z.string(),
    body: z.string(),
  }),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: "/conversations",
    body: {
      from: {
        type: "user",
        id: "user-123",
      },
      body: "I need help with my order",
    },
  },
  { response: ConversationResponseSchema },
);
```

### Reply to a Conversation

```typescript
const ReplyResponseSchema = z.object({
  type: z.literal("conversation"),
  id: z.string(),
  conversation_parts: z.object({
    type: z.literal("conversation_part.list"),
    conversation_parts: z.array(
      z.object({
        type: z.string(),
        id: z.string(),
        body: z.string(),
        created_at: z.number(),
      }),
    ),
  }),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: `/conversations/${conversationId}/reply`,
    body: {
      message_type: "comment",
      type: "admin",
      admin_id: "admin-123",
      body: "Thanks for reaching out! Let me help you with that.",
    },
  },
  { response: ReplyResponseSchema },
);
```

### Add Tags to a Contact

```typescript
const TagResponseSchema = z.object({
  type: z.literal("tag"),
  id: z.string(),
  name: z.string(),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: `/contacts/${contactId}/tags`,
    body: {
      id: "tag-id-123", // Tag ID to add
    },
  },
  { response: TagResponseSchema },
);
```

### Create a Note on a Contact

```typescript
const NoteResponseSchema = z.object({
  type: z.literal("note"),
  id: z.string(),
  created_at: z.number(),
  body: z.string(),
});

const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: `/contacts/${contactId}/notes`,
    body: {
      body: "Customer called about billing issue. Resolved.",
      admin_id: "admin-123",
    },
  },
  { response: NoteResponseSchema },
);
```

## Trace Metadata

All methods accept an optional `metadata` parameter as the last argument for diagnostics labeling. See the [root SDK README](../../../README.md#trace-metadata) for details.

## Common Pitfalls

### No Specialized Methods

```typescript
// WRONG - These methods do not exist
await intercom.createContact({ ... });
await intercom.sendMessage({ ... });

// CORRECT - Use apiRequest
await ctx.integrations.intercom.apiRequest(
  { method: "POST", path: "/contacts", body: { ... } },
  { response: ContactResponseSchema }
);
```

### Contact Role

Contacts must have a `role` of "user" or "lead":

```typescript
// Users - identified customers
const user = {
  role: "user",
  email: "customer@example.com",
  external_id: "your-user-id-123",
};

// Leads - anonymous or prospective customers
const lead = {
  role: "lead",
  email: "prospect@example.com",
};
```

### Search Query Syntax

Intercom uses a specific query structure:

```typescript
// Simple query
const simpleQuery = {
  query: {
    field: "email",
    operator: "=",
    value: "user@example.com",
  },
};

// Compound query (AND)
const andQuery = {
  query: {
    operator: "AND",
    value: [
      { field: "email", operator: "~", value: "@example.com" },
      { field: "role", operator: "=", value: "user" },
    ],
  },
};

// Operators: =, !=, ~, !~, <, >, IN, NIN
```

### Message Types

Different message types for different use cases:

```typescript
// In-app message
const inApp = { message_type: "inapp" };

// Email
const email = { message_type: "email", subject: "Subject line" };

// Conversation reply
const reply = { message_type: "comment" };
```

### Admin ID Required for Some Operations

Many operations require an admin ID:

```typescript
const result = await ctx.integrations.intercom.apiRequest(
  {
    method: "POST",
    path: `/conversations/${id}/reply`,
    body: {
      type: "admin",
      admin_id: "12345", // Required!
      message_type: "comment",
      body: "Response text",
    },
  },
  { response: schema },
);
```

### Rate Limits

Intercom has rate limits (varies by plan):

```typescript
// Check headers for rate limit info:
// X-RateLimit-Limit
// X-RateLimit-Remaining
// X-RateLimit-Reset
```

## Error Handling

```typescript
import { RestApiValidationError } from "@superblocksteam/sdk-api";

try {
  const result = await ctx.integrations.intercom.apiRequest(
    { method: "POST", path: "/contacts", body: { ... } },
    { response: ContactResponseSchema }
  );
} catch (error) {
  if (error instanceof RestApiValidationError) {
    console.error("Validation failed:", error.details.zodError);
  }
}
```

## API Reference

- [Intercom API Documentation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/)
- [Contacts](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/contacts/)
- [Conversations](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/conversations/)
- [Messages](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/messages/)
