# Hubspot

> Complete HubSpot CRM integration via REST API. Use for managing contacts, companies, deals, pipelines, associations, notes, meetings, tasks, and search. Full CRUD operations with verified API patterns.

- Skill: `shakudo-io/hubspot` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add shakudo-io/hubspot`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shakudo-io/hubspot/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: Shakudo-io (https://skillmd.com/u/shakudo-io)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/shakudo-io/hubspot

---


# HubSpot CRM Skill

Complete HubSpot CRM REST API integration for Contacts, Companies, Deals, Pipelines, Associations, Engagements (Notes, Meetings, Tasks, Calls), Properties, and Search.

## Why This Skill Exists

HubSpot's official MCP is in beta and read-only. This skill provides full CRUD operations via direct REST API calls, giving agents complete control over CRM data.

## Quick Start

```bash
# Set your Personal Access Key
export HUBSPOT_PAK="pat-na1-your-key-here"

# List contacts
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/contacts?limit=10" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'

# Search for contacts by email domain
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{"filterGroups":[{"filters":[{"propertyName":"email","operator":"CONTAINS_TOKEN","value":"example.com"}]}],"limit":10}' | jq '.'

# Create a contact
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{"properties":{"email":"new@example.com","firstname":"John","lastname":"Doe"}}' | jq '.'
```

---

## Prerequisites & Authentication

### Personal Access Key (PAK)

HubSpot uses Personal Access Keys for API authentication. Get one from:
**Settings > Integrations > Private Apps > Create private app**

```bash
export HUBSPOT_PAK="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```

### Authentication Header

All API calls use Bearer token authentication:
```bash
curl -H "Authorization: Bearer $HUBSPOT_PAK" -H "Content-Type: application/json" ...
```

### API Base URL

```
https://api.hubapi.com
```

### Required Scopes

Different operations require different scopes. Common ones:

| Scope | Operations |
|-------|------------|
| `crm.objects.contacts.read` | Read contacts |
| `crm.objects.contacts.write` | Create/update/delete contacts |
| `crm.objects.companies.read` | Read companies |
| `crm.objects.companies.write` | Create/update/delete companies |
| `crm.objects.deals.read` | Read deals |
| `crm.objects.deals.write` | Create/update/delete deals |
| `crm.schemas.contacts.read` | Read contact properties |
| `sales-email-read` | Read email engagements |
| `crm.objects.owners.read` | Read owners |
| `tickets` | Read/write tickets |

---

# Part 1: Contacts

## List Contacts

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/contacts?limit=10" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

### With Specific Properties

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/contacts?limit=10&properties=email,firstname,lastname,phone,company,lifecyclestage" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "id": "14401",
      "properties": {
        "email": "john@example.com",
        "firstname": "John",
        "lastname": "Doe",
        "company": "Acme Inc",
        "phone": "(555) 123-4567",
        "lifecyclestage": "lead"
      },
      "createdAt": "2022-02-02T21:53:24.031Z",
      "updatedAt": "2024-10-04T20:29:25.876Z",
      "archived": false
    }
  ],
  "paging": {
    "next": {
      "after": "14452"
    }
  }
}
```

## Get Single Contact

```bash
# By ID
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/contacts/14401?properties=email,firstname,lastname,phone,company" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'

# By email (use idProperty parameter)
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/contacts/john@example.com?idProperty=email&properties=firstname,lastname,company" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Create Contact

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "email": "newcontact@example.com",
      "firstname": "Jane",
      "lastname": "Smith",
      "phone": "555-1234",
      "company": "Tech Corp",
      "lifecyclestage": "lead"
    }
  }' | jq '.'
```

**Response:**
```json
{
  "id": "196231033608",
  "properties": {
    "email": "newcontact@example.com",
    "firstname": "Jane",
    "lastname": "Smith",
    "lifecyclestage": "lead"
  },
  "createdAt": "2026-01-26T16:38:26.645Z"
}
```

## Update Contact

```bash
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/contacts/196231033608" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "company": "New Company Inc",
      "phone": "555-9999",
      "lifecyclestage": "opportunity"
    }
  }' | jq '.'
```

## Delete (Archive) Contact

```bash
curl -s -X DELETE "https://api.hubapi.com/crm/v3/objects/contacts/196231033608" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json"
# Returns HTTP 204 No Content on success
```

---

# Part 2: Companies

## List Companies

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/companies?limit=10&properties=name,domain,industry,city,state" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Get Single Company

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/companies/7992218231?properties=name,domain,industry,numberofemployees,annualrevenue" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Create Company

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/companies" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "name": "New Tech Company",
      "domain": "newtechcompany.com",
      "industry": "Technology",
      "city": "San Francisco",
      "state": "CA",
      "numberofemployees": "50"
    }
  }' | jq '.'
```

## Update Company

```bash
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/companies/7992218231" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "numberofemployees": "100",
      "annualrevenue": "5000000"
    }
  }' | jq '.'
```

## Delete Company

```bash
curl -s -X DELETE "https://api.hubapi.com/crm/v3/objects/companies/7992218231" \
  -H "Authorization: Bearer $HUBSPOT_PAK"
```

---

# Part 3: Deals

## List Deals

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/deals?limit=10&properties=dealname,amount,dealstage,closedate,pipeline" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "id": "8001924129",
      "properties": {
        "amount": "10000",
        "closedate": "2022-06-11T11:57:20.963Z",
        "dealname": "Enterprise Deal",
        "dealstage": "closedwon",
        "pipeline": "default"
      }
    }
  ]
}
```

## Get Single Deal

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/deals/8001924129?properties=dealname,amount,dealstage,closedate,pipeline,hubspot_owner_id" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Create Deal

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/deals" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "dealname": "New Enterprise Deal",
      "amount": "50000",
      "dealstage": "appointmentscheduled",
      "pipeline": "default",
      "closedate": "2026-06-30"
    }
  }' | jq '.'
```

## Update Deal (Move Through Pipeline)

```bash
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/deals/8001924129" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "dealstage": "qualifiedtobuy",
      "amount": "75000"
    }
  }' | jq '.'
```

## Delete Deal

```bash
curl -s -X DELETE "https://api.hubapi.com/crm/v3/objects/deals/8001924129" \
  -H "Authorization: Bearer $HUBSPOT_PAK"
```

---

# Part 4: Pipelines

## List Deal Pipelines

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/pipelines/deals" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response (example):**
```json
{
  "results": [
    {
      "id": "default",
      "label": "Sales Pipeline",
      "stages": [
        {"id": "14960226", "label": "Disco 1 - 3/8 MEDDPICC", "displayOrder": 0},
        {"id": "appointmentscheduled", "label": "Disco 2 - 6/8 MEDDPICC", "displayOrder": 1},
        {"id": "qualifiedtobuy", "label": "Disco 3 - 8/8 MEDDPICC", "displayOrder": 2},
        {"id": "contractsent", "label": "Contracting", "displayOrder": 3},
        {"id": "closedwon", "label": "Closed won", "displayOrder": 5},
        {"id": "closedlost", "label": "Closed lost", "displayOrder": 6}
      ]
    }
  ]
}
```

## Get Specific Pipeline

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/pipelines/deals/default" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

---

# Part 5: Search

HubSpot's Search API is powerful for filtering CRM objects.

## Search Contacts by Email Domain

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [{
        "propertyName": "email",
        "operator": "CONTAINS_TOKEN",
        "value": "example.com"
      }]
    }],
    "properties": ["email", "firstname", "lastname", "company"],
    "limit": 20
  }' | jq '.'
```

## Search Companies by Industry

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/companies/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [{
        "propertyName": "industry",
        "operator": "EQ",
        "value": "Technology"
      }]
    }],
    "properties": ["name", "domain", "industry", "numberofemployees"],
    "limit": 20
  }' | jq '.'
```

## Search Deals by Stage and Amount

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/deals/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [
        {"propertyName": "dealstage", "operator": "EQ", "value": "qualifiedtobuy"},
        {"propertyName": "amount", "operator": "GTE", "value": "10000"}
      ]
    }],
    "properties": ["dealname", "amount", "dealstage", "closedate"],
    "sorts": [{"propertyName": "amount", "direction": "DESCENDING"}],
    "limit": 20
  }' | jq '.'
```

## Search with OR Logic (Multiple Filter Groups)

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [
      {"filters": [{"propertyName": "lifecyclestage", "operator": "EQ", "value": "lead"}]},
      {"filters": [{"propertyName": "lifecyclestage", "operator": "EQ", "value": "opportunity"}]}
    ],
    "properties": ["email", "firstname", "lastname", "lifecyclestage"],
    "limit": 50
  }' | jq '.'
```

### Search Operators

| Operator | Description | Example |
|----------|-------------|---------|
| `EQ` | Equals | `"value": "lead"` |
| `NEQ` | Not equals | `"value": "customer"` |
| `LT` | Less than | `"value": "100"` |
| `LTE` | Less than or equal | `"value": "100"` |
| `GT` | Greater than | `"value": "1000"` |
| `GTE` | Greater than or equal | `"value": "1000"` |
| `CONTAINS_TOKEN` | Contains (for text/email) | `"value": "example.com"` |
| `NOT_CONTAINS_TOKEN` | Does not contain | `"value": "spam"` |
| `HAS_PROPERTY` | Property has any value | (no value needed) |
| `NOT_HAS_PROPERTY` | Property is empty | (no value needed) |
| `BETWEEN` | Between two values | `"value": "100", "highValue": "1000"` |

---

# Part 6: Associations

Associations link CRM objects together (contacts to companies, deals to contacts, etc.).

## Get Associations

```bash
# Get companies associated with a contact
curl -s -X GET "https://api.hubapi.com/crm/v4/objects/contacts/14401/associations/companies" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'

# Get contacts associated with a deal
curl -s -X GET "https://api.hubapi.com/crm/v4/objects/deals/8001924129/associations/contacts" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "toObjectId": 7993011870,
      "associationTypes": [
        {"category": "HUBSPOT_DEFINED", "typeId": 1, "label": "Primary"}
      ]
    }
  ]
}
```

## Create Association

```bash
# Associate contact with company (Primary)
curl -s -X PUT "https://api.hubapi.com/crm/v4/objects/contacts/196246562371/associations/companies/49716553474" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '[{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 1}]' | jq '.'

# Associate deal with contact
curl -s -X PUT "https://api.hubapi.com/crm/v4/objects/deals/8001924129/associations/contacts/14401" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '[{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 3}]' | jq '.'
```

### Common Association Type IDs

| From | To | TypeId | Label |
|------|-----|--------|-------|
| Contact | Company | 1 | Primary |
| Contact | Company | 279 | Secondary |
| Deal | Contact | 3 | Deal to Contact |
| Deal | Company | 5 | Deal to Company |
| Contact | Deal | 4 | Contact to Deal |

## Delete Association

```bash
curl -s -X DELETE "https://api.hubapi.com/crm/v4/objects/contacts/14401/associations/companies/7993011870" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json"
```

---

# Part 7: Engagements (Notes, Meetings, Tasks, Calls)

## Notes

### List Notes

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/notes?limit=10&properties=hs_note_body,hs_timestamp" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

### Create Note

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/notes" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_note_body": "Called customer about renewal. They are interested in upgrading.",
      "hs_timestamp": "2026-01-26T12:00:00.000Z"
    }
  }' | jq '.'
```

### Associate Note with Contact

```bash
# First create note, get the ID, then associate
curl -s -X PUT "https://api.hubapi.com/crm/v4/objects/notes/NOTE_ID/associations/contacts/CONTACT_ID" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '[{"associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 202}]' | jq '.'
```

## Meetings

### List Meetings

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/meetings?limit=10&properties=hs_meeting_title,hs_meeting_start_time,hs_meeting_end_time,hs_meeting_outcome" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

### Create Meeting

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/meetings" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_meeting_title": "Discovery Call",
      "hs_meeting_start_time": "2026-02-01T14:00:00.000Z",
      "hs_meeting_end_time": "2026-02-01T15:00:00.000Z",
      "hs_meeting_outcome": "SCHEDULED"
    }
  }' | jq '.'
```

## Tasks

### List Tasks

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/tasks?limit=10&properties=hs_task_subject,hs_task_status,hs_task_priority,hs_timestamp" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

### Create Task

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/tasks" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_task_subject": "Follow up with customer",
      "hs_task_status": "NOT_STARTED",
      "hs_task_priority": "HIGH",
      "hs_timestamp": "2026-02-01T09:00:00.000Z"
    }
  }' | jq '.'
```

### Update Task Status

```bash
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/tasks/TASK_ID" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_task_status": "COMPLETED"
    }
  }' | jq '.'
```

## Calls

### List Calls

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/calls?limit=10&properties=hs_call_title,hs_call_status,hs_call_duration" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

### Create Call Record

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/calls" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_call_title": "Outbound sales call",
      "hs_call_body": "Discussed pricing and next steps",
      "hs_call_status": "COMPLETED",
      "hs_call_duration": "1800000",
      "hs_timestamp": "2026-01-26T10:00:00.000Z"
    }
  }' | jq '.'
```

---

# Part 8: Owners

Owners are HubSpot users who can be assigned to CRM records.

## List Owners

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/owners?limit=10" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "id": "75464028",
      "email": "user@company.com",
      "type": "PERSON",
      "firstName": "John",
      "lastName": "Smith",
      "userId": 75464028,
      "createdAt": "2024-12-17T21:11:20.407Z",
      "teams": [
        {"id": "38063404", "name": "Sales Team", "primary": true}
      ]
    }
  ]
}
```

## Get Single Owner

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/owners/75464028" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Get Owner by Email

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/owners?email=user@company.com" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

---

# Part 9: Tickets

## List Tickets

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/tickets?limit=10&properties=subject,hs_ticket_priority,hs_pipeline_stage,content" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "id": "2856139557",
      "properties": {
        "subject": "Support Request - Integration Issue",
        "hs_ticket_priority": "HIGH",
        "hs_pipeline_stage": "1"
      }
    }
  ]
}
```

## Create Ticket

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/tickets" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "subject": "Customer Support Request",
      "content": "Customer needs help with API integration",
      "hs_ticket_priority": "HIGH",
      "hs_pipeline_stage": "1"
    }
  }' | jq '.'
```

## Update Ticket

```bash
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/tickets/TICKET_ID" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_ticket_priority": "LOW",
      "hs_pipeline_stage": "2"
    }
  }' | jq '.'
```

## Search Tickets

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/tickets/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [{
        "propertyName": "hs_ticket_priority",
        "operator": "EQ",
        "value": "HIGH"
      }]
    }],
    "properties": ["subject", "hs_ticket_priority", "hs_pipeline_stage"],
    "limit": 20
  }' | jq '.'
```

---

# Part 10: Emails

Email engagements track email communications in HubSpot.

## List Emails

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/emails?limit=10&properties=hs_email_subject,hs_email_direction,hs_email_status,hs_email_text" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "results": [
    {
      "id": "19331427252",
      "properties": {
        "hs_email_direction": "EMAIL",
        "hs_email_status": "SENT",
        "hs_email_subject": "Re: Follow up on our meeting"
      }
    }
  ]
}
```

### Email Direction Values

| Value | Description |
|-------|-------------|
| `EMAIL` | Outbound email sent |
| `INCOMING_EMAIL` | Inbound email received |
| `FORWARDED_EMAIL` | Forwarded email |

## Get Single Email

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/objects/emails/19331427252?properties=hs_email_subject,hs_email_text,hs_email_html,hs_email_direction" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Search Emails

```bash
# Find emails by subject
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/emails/search" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [{
        "propertyName": "hs_email_subject",
        "operator": "CONTAINS_TOKEN",
        "value": "meeting"
      }]
    }],
    "properties": ["hs_email_subject", "hs_email_direction", "hs_email_status"],
    "limit": 20
  }' | jq '.'
```

## Get Emails for a Contact

```bash
# First get associations, then fetch emails
curl -s -X GET "https://api.hubapi.com/crm/v4/objects/contacts/CONTACT_ID/associations/emails" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

---

# Part 11: Properties

## List Properties for Object Type

```bash
# Contact properties
curl -s -X GET "https://api.hubapi.com/crm/v3/properties/contacts" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.results | length'

# Company properties
curl -s -X GET "https://api.hubapi.com/crm/v3/properties/companies" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.results[:5]'

# Deal properties
curl -s -X GET "https://api.hubapi.com/crm/v3/properties/deals" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.results | map(.name)'
```

## Get Single Property

```bash
curl -s -X GET "https://api.hubapi.com/crm/v3/properties/contacts/email" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

## Create Custom Property

```bash
curl -s -X POST "https://api.hubapi.com/crm/v3/properties/contacts" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer_tier",
    "label": "Customer Tier",
    "type": "enumeration",
    "fieldType": "select",
    "groupName": "contactinformation",
    "options": [
      {"label": "Bronze", "value": "bronze", "displayOrder": 1},
      {"label": "Silver", "value": "silver", "displayOrder": 2},
      {"label": "Gold", "value": "gold", "displayOrder": 3}
    ]
  }' | jq '.'
```

---

# Part 12: Account Info

## Get Account Details

```bash
curl -s -X GET "https://api.hubapi.com/account-info/v3/details" \
  -H "Authorization: Bearer $HUBSPOT_PAK" \
  -H "Content-Type: application/json" | jq '.'
```

**Response:**
```json
{
  "portalId": 21367798,
  "accountType": "STANDARD",
  "timeZone": "US/Eastern",
  "companyCurrency": "USD",
  "uiDomain": "app.hubspot.com"
}
```

---

# Quick Reference

## Endpoints Summary

| Action | Method | Endpoint |
|--------|--------|----------|
| List objects | GET | `/crm/v3/objects/{objectType}` |
| Get object | GET | `/crm/v3/objects/{objectType}/{id}` |
| Create object | POST | `/crm/v3/objects/{objectType}` |
| Update object | PATCH | `/crm/v3/objects/{objectType}/{id}` |
| Delete object | DELETE | `/crm/v3/objects/{objectType}/{id}` |
| Search | POST | `/crm/v3/objects/{objectType}/search` |
| Get associations | GET | `/crm/v4/objects/{fromType}/{id}/associations/{toType}` |
| Create association | PUT | `/crm/v4/objects/{fromType}/{id}/associations/{toType}/{toId}` |
| List pipelines | GET | `/crm/v3/pipelines/{objectType}` |
| List properties | GET | `/crm/v3/properties/{objectType}` |
| List owners | GET | `/crm/v3/owners` |
| Account info | GET | `/account-info/v3/details` |

## Object Types

| Object | objectType value |
|--------|------------------|
| Contacts | `contacts` |
| Companies | `companies` |
| Deals | `deals` |
| Tickets | `tickets` |
| Notes | `notes` |
| Meetings | `meetings` |
| Tasks | `tasks` |
| Calls | `calls` |
| Emails | `emails` |

## Pagination

All list endpoints support pagination:

```bash
curl "https://api.hubapi.com/crm/v3/objects/contacts?limit=100&after=14452" \
  -H "Authorization: Bearer $HUBSPOT_PAK"
```

- `limit`: Max 100 per request
- `after`: Cursor from previous response's `paging.next.after`

## Rate Limits

- **Standard:** 100 requests per 10 seconds
- **Daily:** Based on subscription tier (typically 500k/day for Pro)
- **Search:** 4 requests per second

When rate limited, response includes:
```json
{
  "status": "error",
  "message": "You have reached your secondly limit.",
  "category": "RATE_LIMITS"
}
```

## Error Handling

| HTTP Code | Meaning | Action |
|-----------|---------|--------|
| 200/201 | Success | Parse response |
| 204 | Success (no content) | Delete succeeded |
| 400 | Bad request | Check request body/params |
| 401 | Unauthorized | Check PAK token |
| 403 | Forbidden | Missing required scope |
| 404 | Not found | Object doesn't exist |
| 409 | Conflict | Duplicate (e.g., email exists) |
| 429 | Rate limited | Wait and retry |

### Common Error Response

```json
{
  "status": "error",
  "message": "This app hasn't been granted all required scopes",
  "category": "MISSING_SCOPES",
  "errors": [{
    "message": "One or more of the following scopes are required.",
    "context": {
      "requiredGranularScopes": ["crm.objects.owners.read"]
    }
  }]
}
```

---

## Related Resources

- [HubSpot API Docs](https://developers.hubspot.com/docs/api/crm)
- [Authentication](https://developers.hubspot.com/docs/api/private-apps)
- [Properties API](https://developers.hubspot.com/docs/api/crm/properties)
- [Search API](https://developers.hubspot.com/docs/api/crm/search)
- [Associations API](https://developers.hubspot.com/docs/api/crm/associations)
- [Rate Limits](https://developers.hubspot.com/docs/api/usage-details)

