API Documentation

🏒 Webhook Integration Guide

Webhook Integration Guide | Taskee Portal API
portalapi.taskee.ai Β· API 2.0
Webhook Docs

Webhook Integration Guide

Everything you need to connect your application to real-time event notifications from the Taskee Portal API β€” from setup to production-grade reliability.

What are Webhooks?

Webhooks are a way for applications to communicate in real-time. Think of them as automatic notifications that are sent to your application when something happens in our platform β€” no polling required.

Real-World Example

Imagine you're building a task management or e-commerce app integrated with Taskee:

  • β†’ When a customer places an order β€” you get a webhook notification
  • β†’ When the order status changes β€” you get another webhook notification
  • β†’ When the payment is processed β€” you get yet another notification

This way, your app stays updated without constantly asking "has anything changed?"

Getting Started

Step 1: Create Your Webhook Endpoint

First, you need a public URL that can receive webhook notifications. Choose one of the following options:

Option A

Cloud Service

  • Heroku β€” Deploy a simple web app
  • AWS Lambda β€” Serverless function
  • Google Cloud Functions β€” Serverless function
  • Vercel β€” Easy deployment platform
Option B

Testing Services

  • webhook.site β€” Temporary URL for testing
  • ngrok β€” Expose local server to the internet
Option C

Your Own Server

  • Deploy a web application on your server
  • Ensure it's accessible via HTTPS

Step 2: Create a Simple Webhook Handler

Here's a basic example using Node.js and Express:

const express = require('express')
const app = express()

// Parse JSON requests
app.use(express.json())

// Your webhook endpoint
app.post('/webhooks', (req, res) => {
  console.log('Received webhook:', req.body)

  const eventType = req.body.type
  const eventData = req.body.data

  switch (eventType) {
    case 'ContactCreate':
      console.log('New contact created:', eventData)
      break
    case 'ContactUpdate':
      console.log('Contact updated:', eventData)
      break
    default:
      console.log('Unknown event type:', eventType)
  }

  // Always respond with 200 OK
  res.status(200).json({ success: true })
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
  console.log(`Webhook server running on port ${PORT}`)
})

Step 3: Test Your Endpoint

Before connecting to the Taskee Portal API, test your endpoint with a curl request:

curl -X POST https://your-app.com/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ContactCreate",
    "timestamp": "2025-01-28T14:35:00.000Z",
    "webhookId": "test-123",
    "data": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "[email protected]"
    }
  }'

Available Webhook Events

Taskee Portal API offers a comprehensive set of webhook events that cover all major activities in our platform.

Event Categories

Contact Events β€” creation, updates, deletion, tag changes
Opportunity Events β€” lifecycle management and status updates
Task Events β€” task creation, completion, and deletion
Appointment Events β€” calendar scheduling and updates
Invoice Events β€” full lifecycle from creation to payment
Product Events β€” product catalog management
Association Events β€” relationship management between records
Location Events β€” location creation and updates
User Events β€” user account management
And more… β€” see the full event reference
πŸ“– Detailed Event Documentation
For complete payload structures, field descriptions, data types, and sample JSON responses for every event, refer to the full Taskee Portal API Webhook Reference documentation.

Security: Verifying Webhook Authenticity

Why Verification is Important

Webhooks can be spoofed by malicious actors. Always verify that webhooks are coming from the Taskee Portal API before processing them.

How to Verify

We use a private key to sign our webhook payloads. You can verify the signature using our public key. Each request includes a digital signature in the x-wh-signature header.

Taskee Portal API Public Key

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAokvo/r9tVgcfZ5DysOSC
Frm602qYV0MaAiNnX9O8KxMbiyRKWeL9JpCpVpt4XHIcBOK4u3cLSqJGOLaPuXw6
dO0t6Q/ZVdAV5Phz+ZtzPL16iCGeK9po6D6JHBpbi989mmzMryUnQJezlYJ3DVfB
csedpinheNnyYeFXolrJvcsjDtfAeRx5ByHQmTnSdFUzuAnC9/GepgLT9SM4nCpv
uxmZMxrJt5Rw+VUaQ9B8JSvbMPpez4peKaJPZHBbU3OdeCVx5klVXXZQGNHOs8gF
3kvoV5rTnXV0IknLBXlcKKAQLZcY/Q9rG6Ifi9c+5vqlvHPCUJFT5XUGG5RKgOKU
J062fRtN+rLYZUV+BjafxQauvC8wSWeYja63VSUruvmNj8xkx2zE/Juc+yjLjTXp
IocmaiFeAO6fUtNjDeFVkhf5LNb59vECyrHD2SQIrhgXpO4Q3dVNA5rw576PwTzN
h/AMfHKIjE4xQA1SZuYJmNnmVZLIZBlQAF9Ntd03rfadZ+yDiOXCCs9FkHibELhC
HULgCsnuDJHcrGNd5/Ddm5hxGQ0ASitgHeMZ0kcIOwKDOzOU53lDza6/Y09T7sYJ
PQe7z0cvj7aE4B+Ax1ZoZGPzpJlZtGXCsu9aTEGEnKzmsFqwcSsnw3JB31IGKAyk
T1hhTiaCeIY/OwwwNUY2yvcCAwEAAQ==
-----END PUBLIC KEY-----

Here's how to verify the x-wh-signature in Node.js:

const crypto = require('crypto')
const publicKey = `<use_the_above_key>`

function verifySignature(payload, signature) {
  const verifier = crypto.createVerify('SHA256')
  verifier.update(payload)
  verifier.end()
  return verifier.verify(publicKey, signature, 'base64')
}

// Example usage
const payload = JSON.stringify({
  "timestamp": "2025-01-28T14:35:00Z",
  "webhookId": "abc123xyz",
  // ...other webhook data
})

const signature = "<received-x-wh-signature>"
const isValid = verifySignature(payload, signature)
return isValid

Setting Up Your Integration

1

Create Your OAuth Application

Create an OAuth application via the Taskee Portal API dashboard. This gives you a webhook URL to receive notifications, access to specific data based on scopes, and the ability to subscribe to specific events.

2

Configure Your Webhook URL

After filling in all mandatory information, navigate to the Auth section under Advanced Settings. Select the scope of your application from the dropdown menu.

πŸ“Έ OAuth Scopes Configuration Screenshot
3

Choose Your Events

After defining the scopes, go to the Webhook section under Advanced Settings. Toggle on and paste your webhook URL against the events you wish to receive notifications for.

πŸ“Έ Webhook URL Configuration Screenshot

Handling Webhooks Reliably

Best Practices

  • ⚑
    Always Respond Quickly Process webhooks asynchronously if needed. Return 200 OK immediately and do heavy processing in the background.
  • πŸ”
    Handle Duplicates Store webhook IDs to prevent duplicate processing. Make your processing idempotent β€” safe to run multiple times with the same result.
  • πŸ“‹
    Log Everything Log all incoming webhooks, processing results, and errors for debugging. Good observability is essential for production reliability.

Example Implementation

const express = require('express')
const crypto = require('crypto')
const app = express()
app.use(express.json())

// Store processed webhook IDs (use a database in production)
const processedWebhooks = new Set()

app.post('/webhooks', async (req, res) => {
  try {
    // 1. Verify signature
    const signature = req.headers['x-wh-signature']
    if (!verifyWebhookSignature(req.body, signature)) {
      return res.status(401).json({ error: 'Invalid signature' })
    }

    // 2. Check for duplicates
    if (processedWebhooks.has(req.body.webhookId)) {
      return res.status(200).json({ message: 'Already processed' })
    }

    // 3. Log the webhook
    console.log('Processing webhook:', req.body.type, req.body.webhookId)

    // 4. Process asynchronously (don't block the response)
    setImmediate(() => { processWebhookAsync(req.body) })

    // 5. Mark as processed
    processedWebhooks.add(req.body.webhookId)

    // 6. Respond immediately
    res.status(200).json({ success: true })
  } catch (error) {
    console.error('Webhook processing error:', error)
    res.status(200).json({ success: false, error: 'Processing failed' })
  }
})

async function processWebhookAsync(webhook) {
  try {
    switch (webhook.type) {
      case 'ContactCreate': await handleNewContact(webhook.data); break
      case 'ContactUpdate': await handleContactUpdate(webhook.data); break
    }
  } catch (error) {
    console.error('Failed to process webhook:', webhook.webhookId, error)
  }
}

Error Handling & Retries

How Our Retry System Works

We only retry webhook deliveries when your endpoint returns a 429 status code. All other failure types are not retried.

Parameter Value
Retry Trigger 429 Rate limit only
Retry Interval 10 minutes between attempts + jitter
Max Retries 6 attempts for 429 errors
Total Duration ~1 hour 10 minutes (6 Γ— 10 min + initial + jitter)
Retry Condition Only continues if 429 status codes keep coming back
Scheduling Distributed scheduling with random jitter
⚠ Important: We do not retry webhooks that return 5xx server errors. These are treated as permanent failures.

Understanding Jitter

What is jitter? Jitter is a random delay added to retry attempts to prevent the "thundering herd" problem. When multiple webhooks fail with 429 status codes simultaneously, without jitter they would all retry at the same time β€” potentially overwhelming your server again.

Our distributed scheduling system applies random jitter to each retry attempt. The jitter can vary significantly β€” from seconds to minutes β€” ensuring a natural distribution that spreads retry load over time.

What You Should Do

Return 200 for success:

res.status(200).json({ success: true })

Return 200 even for processing errors β€” to acknowledge receipt:

try {
  await processWebhook(req.body)
  res.status(200).json({ success: true })
} catch (error) {
  console.error('Processing failed:', error)
  // Still return 200 to acknowledge receipt
  res.status(200).json({ success: false, error: 'Processing failed' })
}

Only return error codes for real infrastructure issues:

StatusMeaning
408Your server is too slow to respond
429You're receiving too many requests (triggers retry)
5xxYour server is down or broken (no retry)

Testing Your Integration

The best way to verify your webhook integration is to use the Webhook Logs Dashboard. This dashboard provides comprehensive monitoring and troubleshooting for all webhook deliveries to your application.

πŸ“Έ Webhook Logs Dashboard Screenshot

The Webhook Logs Dashboard allows you to:

  • πŸ“‹
    View all webhook events sent to your application and track success/failure rates
  • πŸ”
    Search for specific webhook IDs, filter by event type and status codes
  • πŸ“¦
    View detailed payload information and monitor retry attempts
  • πŸ› 
    Investigate delivery issues in real-time

Accessing the Dashboard

1

Navigate to your Application Dashboard

2

Select the app you want to check logs for

3

Go to Insights from the left menu

4

Click on Logs β€” the Webhooks tab will be active by default

Common Issues & Solutions

"Invalid signature" errors
Solution: Make sure you're using the correct public key and verifying the entire payload without modification.
Duplicate webhook processing
Solution: Store webhook IDs in a persistent store and check for duplicates before processing each webhook.
Webhooks timing out
Solution: Process webhooks asynchronously using setImmediate or a queue, and respond with 200 OK as quickly as possible.
Missing webhook events
Solution: Check that you've subscribed to the correct events in your OAuth app configuration under Advanced Settings β†’ Webhook.
Can't access webhook data
Solution: Ensure your OAuth app has the correct scopes for the data you need. Scopes control what data is accessible via webhooks.

Next Steps

  1. Set up your webhook endpoint using one of the examples above
  2. Test with webhook.site to make sure it's working correctly
  3. Create your OAuth application in the Taskee Portal API dashboard
  4. Subscribe to the events you need under Advanced Settings
  5. Deploy your webhook handler to a production server with HTTPS
  6. Monitor and log your webhook processing using the Logs Dashboard

🏒 Authorization

Authorization | portalapi.taskee.ai
portalapi.taskee.ai Β· API 2.0

Private Integrations

Private Integrations allow you to build powerful custom integrations between your portalapi.taskee.ai account and any third-party app β€” securely, with scoped permissions you control.

If you need to connect your account with an external app, you have two options: install a ready-made app from the marketplace, or build your own private integration using the API. Private Integrations are the secure, recommended path for option two.

✦ Key Advantages

πŸ”’
Secure by Design
Restrict the exact scopes and permissions a developer can access on your account. No over-sharing.
⚑
Simple to Generate
Create and manage Private Integration tokens directly from your account settings β€” no complex flows required.
🏒
Scale and Grow
Private Integrations are scalable removing any limitations for growth at portalapi.taskee.ai.
πŸš€
API v2.0 Access
Unlocks the full, current API v2.0 surface β€” more endpoints, more power, actively maintained.

βš– Private Integrations vs API Keys

Feature Private Integrations API Keys
Security Scoped permissions β€” developers only access what you allow Unrestricted access to all account data
API Version API v2.0 β€” current, state-of-the-art API v1.0 β€” end-of-life, no longer maintained
Features Full v2.0 API surface β€” more endpoints and capabilities Limited v1.0 endpoints only

βš– Private Integrations vs OAuth2 Access Tokens

Private Integration tokens are, in essence, static OAuth2 Access Tokens β€” with a simpler generation flow.

Feature Private Integrations OAuth2 Access Tokens
Generation Generated from the UI β€” simple, no code required Programmatic β€” exchange an OAuth code for tokens via API
Lifespan Static/Fixed β€” does not expire unless you explicitly rotate it Expire daily β€” must be refreshed regularly

βš™ How to Use Private Integrations

Private Integration tokens are passed in the Authorization header, exactly like standard OAuth2 Bearer tokens.

Requirements
Parameter Location Type Required Description
Authorization header string required Your Private Integration token, prefixed with Bearer . Example: Bearer pit_xxxxxxxxxxxx
Version header string required API version header. Must be 2021-07-28.
Accept header string optional Response format. Use application/json.
Content-Type header string required for POST/PUT Required when sending a request body. Use application/json.
Request β€” GET Example
cURL
curl --request GET \ --url https://portalapi.taskee.ai/locations/ve9EPM428h8vShlRW1KT \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <YOUR PRIVATE INTEGRATION TOKEN>' \ --header 'Version: 2021-07-28'
Responses
200 OK β€” request succeeded. Returns the requested resource as JSON.
{ "id": "ve9EPM428h8vShlRW1KT", "name": "My Sub-Account", "address": "123 Main St", "city": "Austin", "state": "TX", "country": "US", "timezone": "America/Chicago" }
401 Unauthorized β€” missing or invalid Authorization token.
{ "statusCode": 401, "message": "Invalid token" }
403 Forbidden β€” token lacks the required scope for this endpoint.
{ "statusCode": 403, "message": "Insufficient scopes" }
400 Bad Request β€” malformed request, missing Version header, or invalid parameters.
{ "statusCode": 400, "message": "Missing required header: Version" }

πŸ§ͺ Testing with API Calls

Once your Private Integration is created, test it by pushing data to an endpoint. The example below creates a new contact:

cURL β€” Create Contact
curl --request POST \ --url https://portalapi.taskee.ai/contacts/ \ --header 'Authorization: Bearer <YOUR PRIVATE INTEGRATION TOKEN>' \ --header 'Content-Type: application/json' \ --header 'Version: 2021-07-28' \ --data '{ "firstName": "John", "lastName": "Doe", "email": "[email protected]", "phone": "+1234567890", "locationId": "LOCATION_ID" }'
  • Replace LOCATION_ID with the actual sub-account ID.
  • Replace the Authorization value with your generated Private Integration token.
  • The Version header must always be set to 2021-07-28.

πŸ—‚ Managing Private Integrations

Who can create Private Integrations?

By default, all agency admins can create and manage Private Integrations. You can restrict this permission at the individual user level.

You may apply restrictions at two levels:

  • Allow the agency admin to view and manage the agency's private integrations.
  • Allow the agency admin to view and manage sub-accounts' private integrations.

Where can I find Private Integrations?

Navigate to Agency Settings and look for the Private Integrations section. If it's not visible, ensure the feature is enabled under Labs.

βž• Creating a New Private Integration

1
Click "Create new Integration" from the Private Integrations settings page.
2
Give your integration a name and description so your team knows exactly what it's for.
3
Select the scopes/permissions you want to grant. Choose only what is strictly required for better security.
4
Copy the generated token and share it with your developer or third-party app. You will not be able to view it again.
⚠️
Important: Only share tokens with trusted parties. Never expose them publicly. Copy the token immediately β€” it cannot be retrieved again after leaving the creation screen.

πŸ›‘ Security Best Practices

We recommend rotating your Private Integration tokens every 90 days.

90
Day rotation cycle recommended
7
Day overlap window after rotation
0
Downtime during rotation

How to Rotate Your Token

1
Navigate to Private Integrations under settings and click on your integration.
2
Click "Rotate and expire this token later".
3
Click "Continue" to confirm rotation.
4
Copy the new token and update it in your third-party app.
ℹ️
During the 7-day overlap window, both old and new tokens will work. You can Cancel rotation if more time is needed, or Expire Now once the app has been updated.

🚨 What If My Token Is Compromised?

If you suspect your token has been exposed, rotate it immediately using the following steps:

1
Navigate to Private Integrations under settings and click on your integration.
2
Click "Rotate and expire this token now" β€” this invalidates the old token immediately.
3
Click "Continue" to confirm.
4
Copy the new token and update it in all integrations immediately.
⚠️
Note: Copy the new token immediately after generation β€” it cannot be viewed again after leaving the screen.

✏️ Editing Permissions Without Updating the Token

Yes β€” you can update the integration's name, description, and scopes at any time without generating a new token. The existing token continues to work.

1
Navigate to Private Integrations under settings and select "Edit" from the three-dot menu.
2
Update the name and description as needed. Click "Next".
3
Update the scopes/permissions β€” select only what is required. Click "Update" to save.
ℹ️
Updating permissions does not generate a new token. The existing token remains valid.

πŸ—‘ Deleting a Private Integration

Once you no longer need an integration, delete it to revoke access immediately and keep your account clean.

How to Delete
Navigate to Private Integrations under settings, then select "Delete" from the three-dot menu next to the integration you want to remove. The token will be instantly invalidated.

🏒 CRM & Contacts

Manage contacts, leads, and customer data with full CRUD operations, tagging, and custom fields.

Contacts API | portalapi.taskee.ai
portalapi.taskee.ai Β· API 2.0

Contacts API

Documentation for the Contacts API. Manage contact records β€” create, read, update, delete, upsert, and query contacts across your portalapi.taskee.ai account.

Contacts
GET /contacts/{contactId} Get Contact β–Ό
Description
Retrieves a single contact by its unique ID.
Requirements
Parameter Location Type Required Description
Authorization header string required Bearer token. Example: Bearer {token}
Version header string required API version. Example: 2021-07-28
contactId path string required The unique ID of the contact to retrieve.
Request
HTTP
GET /contacts/{contactId} Authorization: Bearer <token> Version: 2021-07-28
Responses
200 Successful response β€” returns the contact object.
{ "contact": { "id": "contact_abc123", "locationId": "loc_xyz", "firstName": "Jane", "lastName": "Doe", "email": "[email protected]", "phone": "+14155552671", "address1": "123 Main St", "city": "San Francisco", "state": "CA", "country": "US", "postalCode": "94105", "tags": ["lead", "vip"], "dateAdded": "2024-01-15T10:00:00Z", "dateUpdated": "2024-06-01T08:30:00Z" } }
401 Unauthorized β€” invalid or missing token.
400 Bad Request β€” invalid contactId.
PUT /contacts/{contactId} Update Contact β–Ό
Description
Updates a contact record by its ID. Please find the list of acceptable values for the country field in the Country List.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
contactId path string required The unique ID of the contact to update.
firstName body string optional Contact's first name.
lastName body string optional Contact's last name.
email body string optional Contact's email address.
phone body string optional Contact's phone number (E.164 format).
address1 body string optional Street address line 1.
city body string optional City.
state body string optional State or province.
country body string optional Country code (ISO 3166-1 alpha-2). See Country List for accepted values.
postalCode body string optional Postal / ZIP code.
tags body string[] optional Array of tag strings to assign to the contact.
Request
JSON Body
{ "firstName": "Jane", "lastName": "Smith", "email": "[email protected]", "phone": "+14155559876", "country": "US", "tags": ["lead", "newsletter"] }
Responses
200 Contact updated successfully β€” returns updated contact object.
{ "contact": { "id": "contact_abc123", "firstName": "Jane", "lastName": "Smith", "email": "[email protected]", "dateUpdated": "2024-06-10T12:00:00Z" } }
422Unprocessable Entity β€” validation error in request body.
401Unauthorized.
DELETE /contacts/{contactId} Delete Contact β–Ό
Description
Permanently deletes a contact by its unique ID. This action cannot be undone.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
contactId path string required The unique ID of the contact to delete.
Request
HTTP
DELETE /contacts/{contactId} Authorization: Bearer <token> Version: 2021-07-28
Responses
200 Contact deleted successfully.
{ "succeeded": true }
401Unauthorized.
400Bad Request β€” invalid contactId format.
POST /contacts/upsert Upsert Contact β–Ό
Description
Creates or updates a contact based on the "Allow Duplicate Contact" setting at the Location level. If configured to check both Email and Phone, the API identifies an existing contact using the priority sequence defined in the setting, then creates or updates accordingly.

If two separate contacts already exist β€” one with the same email and another with the same phone β€” and an upsert request includes both, the API updates the contact matching the first field in the configured sequence and ignores the second to prevent duplication. Please find acceptable values for the country field in the Country List.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
locationId body string required The ID of the location/sub-account for this contact.
firstName body string optional Contact's first name.
lastName body string optional Contact's last name.
email body string optional Contact's email. Used as a match key for deduplication.
phone body string optional Contact's phone in E.164 format. Used as a match key for deduplication.
country body string optional Country code β€” see Country List for accepted values.
tags body string[] optional Tags to apply to the contact.
Request
JSON Body
{ "locationId": "loc_xyz", "firstName": "John", "lastName": "Doe", "email": "[email protected]", "phone": "+14155551234", "country": "US" }
Responses
200 Contact created or updated β€” returns contact object with action taken.
{ "contact": { "id": "contact_abc123", "locationId": "loc_xyz", "email": "[email protected]", "phone": "+14155551234", "dateAdded": "2024-01-15T10:00:00Z" }, "new": false // false = updated, true = created }
422Unprocessable Entity β€” validation error.
401Unauthorized.
GET /contacts/business/{businessId} Get Contacts By BusinessId β–Ό
Description
Retrieves all contacts associated with a given business ID.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
businessId path string required The unique ID of the business.
limit query number optional Number of results per page. Default: 25, Max: 100.
skip query number optional Number of records to skip for pagination.
Request
HTTP
GET /contacts/business/{businessId}?limit=25&skip=0 Authorization: Bearer <token> Version: 2021-07-28
Responses
200 Returns an array of contact objects for the business.
{ "contacts": [ { "id": "contact_abc123", "firstName": "Alice", "email": "[email protected]" } ], "total": 42 }
401Unauthorized.
POST /contacts/ Create Contact β–Ό
Description
Creates a new contact. Please find the list of acceptable values for the country field in the Country List.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
locationId body string required The ID of the location/sub-account where the contact will be created.
firstName body string optional Contact's first name.
lastName body string optional Contact's last name.
email body string optional Contact's email address.
phone body string optional Contact's phone in E.164 format.
address1 body string optional Street address line 1.
city body string optional City.
state body string optional State or province.
country body string optional Country code β€” see Country List for accepted values.
postalCode body string optional Postal / ZIP code.
tags body string[] optional Tags to assign to the new contact.
source body string optional The source of the contact (e.g., "API", "import").
Request
JSON Body
{ "locationId": "loc_xyz", "firstName": "Bob", "lastName": "Builder", "email": "[email protected]", "phone": "+14085559876", "address1": "456 Oak Ave", "city": "Austin", "state": "TX", "country": "US", "postalCode": "78701", "tags": ["new-lead"], "source": "API" }
Responses
200 Contact created successfully β€” returns the new contact object.
{ "contact": { "id": "contact_new456", "locationId": "loc_xyz", "firstName": "Bob", "lastName": "Builder", "email": "[email protected]", "phone": "+14085559876", "tags": ["new-lead"], "dateAdded": "2024-06-10T15:00:00Z" } }
422Unprocessable Entity β€” validation failed.
401Unauthorized.
GET /contacts/ Get Contacts β–Ό
Description
Retrieves a paginated list of contacts for a given location.
Requirements
ParameterLocationTypeRequiredDescription
Authorization header string required Bearer token.
Version header string required API version. Example: 2021-07-28
locationId query string required The ID of the location to retrieve contacts from.
limit query number optional Number of results per page. Default: 25, Max: 100.
startAfterId query string optional Cursor ID for pagination β€” start results after this contact ID.
startAfter query number optional Timestamp (ms) cursor for pagination.
query query string optional Search query to filter contacts by name, email, or phone.
Request
HTTP
GET /contacts/?locationId=loc_xyz&limit=25 Authorization: Bearer <token> Version: 2021-07-28
Responses
200 Returns paginated list of contacts with metadata.
{ "contacts": [ { "id": "contact_abc123", "locationId": "loc_xyz", "firstName": "Alice", "lastName": "Jones", "email": "[email protected]", "phone": "+14155550001", "tags": ["lead"], "dateAdded": "2024-01-10T08:00:00Z" } ], "total": 200, "startAfterId": "contact_abc123", "startAfter": 1704873600000 }
400Bad Request β€” missing or invalid locationId.
401Unauthorized.