# Segment Client

Track events, identify users, and interact with Segment's customer data platform.

## Methods

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

## Usage

### Track an Event

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

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

const TrackResponseSchema = z.object({
  success: z.boolean(),
});

export default api({
  integrations: {
    segment: segment(PROD_SEGMENT),
  },
  name: "SegmentExample",
  input: z.object({
    userId: z.string(),
    event: z.string(),
    properties: z.record(z.unknown()),
  }),
  output: z.object({
    success: z.boolean(),
  }),
  async run(ctx, { userId, event, properties }) {
    const result = await ctx.integrations.segment.apiRequest(
      {
        method: "POST",
        path: "/v1/track",
        body: {
          userId: userId,
          event: event,
          properties: properties,
          timestamp: new Date().toISOString(),
          context: {
            library: {
              name: "superblocks-sdk",
              version: "1.0.0",
            },
          },
        },
      },
      { response: TrackResponseSchema },
    );

    return { success: result.success };
  },
});
```

### Identify a User

```typescript
const IdentifyResponseSchema = z.object({
  success: z.boolean(),
});

const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/identify",
    body: {
      userId: "user_123",
      traits: {
        email: "john@example.com",
        name: "John Doe",
        plan: "enterprise",
        createdAt: "2024-01-15T10:00:00Z",
        company: {
          id: "company_456",
          name: "Acme Corp",
          industry: "Technology",
        },
      },
      context: {
        ip: "192.168.1.1",
        userAgent: "Mozilla/5.0...",
      },
    },
  },
  { response: IdentifyResponseSchema },
);

console.log(`User identified: ${result.success}`);
```

### Create an Alias

```typescript
const AliasResponseSchema = z.object({
  success: z.boolean(),
});

// Link anonymous user to known user
const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/alias",
    body: {
      previousId: "anonymous_abc123",
      userId: "user_123",
    },
  },
  { response: AliasResponseSchema },
);
```

### Track Page View

```typescript
const PageResponseSchema = z.object({
  success: z.boolean(),
});

const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/page",
    body: {
      userId: "user_123",
      name: "Home",
      category: "Marketing",
      properties: {
        title: "Welcome to Acme",
        url: "https://example.com/",
        path: "/",
        referrer: "https://google.com/",
      },
    },
  },
  { response: PageResponseSchema },
);
```

### Group Users

```typescript
const GroupResponseSchema = z.object({
  success: z.boolean(),
});

const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/group",
    body: {
      userId: "user_123",
      groupId: "company_456",
      traits: {
        name: "Acme Corp",
        industry: "Technology",
        employees: 250,
        plan: "enterprise",
        website: "https://acme.com",
      },
    },
  },
  { response: GroupResponseSchema },
);
```

### Batch Multiple Events

```typescript
const BatchResponseSchema = z.object({
  success: z.boolean(),
});

const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/batch",
    body: {
      batch: [
        {
          type: "identify",
          userId: "user_123",
          traits: { email: "john@example.com" },
        },
        {
          type: "track",
          userId: "user_123",
          event: "Signed Up",
          properties: { plan: "free" },
        },
        {
          type: "track",
          userId: "user_123",
          event: "Onboarding Started",
          properties: { step: 1 },
        },
      ],
      context: {
        library: { name: "superblocks-sdk" },
      },
    },
  },
  { response: BatchResponseSchema },
);
```

### Track Screen View (Mobile)

```typescript
const ScreenResponseSchema = z.object({
  success: z.boolean(),
});

const result = await ctx.integrations.segment.apiRequest(
  {
    method: "POST",
    path: "/v1/screen",
    body: {
      userId: "user_123",
      name: "Dashboard",
      properties: {
        section: "Overview",
        loaded_at: new Date().toISOString(),
      },
      context: {
        device: {
          type: "ios",
          model: "iPhone 15",
          manufacturer: "Apple",
        },
        app: {
          name: "MyApp",
          version: "2.1.0",
          build: "145",
        },
      },
    },
  },
  { response: ScreenResponseSchema },
);
```

## 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 segment.track({ ... });
await segment.identify({ ... });

// CORRECT - Use apiRequest
await ctx.integrations.segment.apiRequest(
  { method: "POST", path: "/v1/track", body: { ... } },
  { response: TrackResponseSchema }
);
```

### userId vs anonymousId

At least one ID is required:

```typescript
// WRONG - No user identifier
const body = {
  event: "Button Clicked",
  properties: { buttonName: "Submit" },
};

// CORRECT - With userId
const body = {
  userId: "user_123",
  event: "Button Clicked",
  properties: { buttonName: "Submit" },
};

// CORRECT - With anonymousId (for unknown users)
const body = {
  anonymousId: "anon_abc123",
  event: "Button Clicked",
  properties: { buttonName: "Submit" },
};

// Can include both
const body = {
  userId: "user_123",
  anonymousId: "anon_abc123", // Links them together
  event: "Button Clicked",
  properties: { buttonName: "Submit" },
};
```

### Event Naming Conventions

Use consistent, descriptive event names:

```typescript
// WRONG - Inconsistent naming
await track({ event: "click_button" });
await track({ event: "SignUp" });
await track({ event: "order-completed" });

// CORRECT - Object Action format (recommended)
await track({ event: "Button Clicked" });
await track({ event: "Account Created" });
await track({ event: "Order Completed" });

// Use past tense for actions
// Good: "Product Added", "Form Submitted", "Page Viewed"
// Avoid: "Add Product", "Submit Form", "View Page"
```

### Reserved Property Names

Some property names have special meaning:

```typescript
const body = {
  userId: "user_123",
  event: "Order Completed",
  properties: {
    // Reserved Segment properties (use these correctly)
    revenue: 99.99, // Total revenue (number)
    currency: "USD", // ISO 4217 code
    value: 99.99, // Generic value (number)
    orderId: "order_789", // Unique order ID

    // Custom properties
    products: [...],
    coupon: "SAVE20",
  },
};
```

### Timestamp Format

Use ISO 8601 format:

```typescript
// WRONG - Unix timestamp
const body = {
  timestamp: Date.now(),
};

// WRONG - Other formats
const body = {
  timestamp: "01/15/2024",
};

// CORRECT - ISO 8601
const body = {
  timestamp: new Date().toISOString(), // "2024-01-15T10:30:00.000Z"
};

// Or specific timestamp
const body = {
  timestamp: "2024-01-15T10:30:00Z",
};
```

### Traits vs Properties

`traits` for identify, `properties` for track:

```typescript
// identify uses "traits"
const identifyBody = {
  userId: "user_123",
  traits: {
    email: "john@example.com",
    name: "John Doe",
  },
};

// track uses "properties"
const trackBody = {
  userId: "user_123",
  event: "Order Completed",
  properties: {
    orderId: "order_789",
    total: 99.99,
  },
};
```

### Batch Size Limits

Batch endpoint has limits:

```typescript
// Maximum 500KB per request
// Maximum 100 events recommended per batch

const events = [...]; // Large array

// Split into chunks
const chunkSize = 100;
for (let i = 0; i < events.length; i += chunkSize) {
  const batch = events.slice(i, i + chunkSize);
  await ctx.integrations.segment.apiRequest(
    {
      method: "POST",
      path: "/v1/batch",
      body: { batch },
    },
    { response: BatchResponseSchema }
  );
}
```

### Context Object

Include context for richer data:

```typescript
const body = {
  userId: "user_123",
  event: "Order Completed",
  properties: { ... },
  context: {
    // Library info
    library: {
      name: "superblocks-sdk",
      version: "1.0.0",
    },
    // User's IP (for geo)
    ip: "192.168.1.1",
    // User agent (for device info)
    userAgent: "Mozilla/5.0...",
    // Locale
    locale: "en-US",
    // Timezone
    timezone: "America/New_York",
    // Campaign info
    campaign: {
      source: "google",
      medium: "cpc",
      name: "spring_sale",
    },
  },
};
```

### Response Always Returns Success

Segment's Tracking API always returns `{success: true}` for valid requests:

```typescript
// The API returns 200 OK with {success: true} even if:
// - User doesn't exist
// - Event is malformed but syntactically valid
// - Destinations fail

// Actual delivery errors appear in Segment's debugger
// or destination logs, not in the API response
```

## Error Handling

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

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

## API Reference

- [Segment HTTP Tracking API](https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/)
- [Track Spec](https://segment.com/docs/connections/spec/track/)
- [Identify Spec](https://segment.com/docs/connections/spec/identify/)
- [Common Fields](https://segment.com/docs/connections/spec/common/)
